什么是 socket?
socket 的原意是“插座”,在计算机通信领域,socket 被翻译为“套接字”,它是计算机之间进行通信的一种约定或一种方式。通过 socket 这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据。
我们把插头插到插座上就能从电网获得电力供应,同样,为了与远程计算机进行数据传输,需要连接到因特网,而 socket 就是用来连接到因特网的工具。
socket 的典型应用就是 Web 服务器和浏览器:浏览器获取用户输入的 URL,向服务器发起请求,服务器分析接收到的 URL,将对应的网页内容返回给浏览器,浏览器再经过解析和渲染,就将文字、图片、视频等元素呈现给用户。
不说那么多废话了,自己了解原理哇,百度查
nuget 包NLog
代码如下:
using NLog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace SocketServer
{
class Program
{
private static Logger logger = LogManager.GetCurrentClassLogger();//nlog
//创建一个和客户端通信的套接字
private static Socket SocketWatch = null;
//定义一个集合,存储客户端信息
private static Dictionary<string, Socket> ClientConnectionItems = new Dictionary<string, Socket> { };
private static Dictionary<string, Socket> BlackClientConnectionItems = new Dictionary<string, Socket> { };//记录黑名单
private static List<string> ReceiveStrList = new List<string>();//记录介绍加密字符串是否一样
private static List<string> ClientIPList = new List<string>();//记录IP地址防止重复连接
private static bool IsRecvidData = false;
private static string keyDe = "12345678";
static void Main(string[] args)
{
//端口号(用来监听的)
int port =8000;
//string host = "127.0.0.1";
//IPAddress ip = IPAddress.Parse(host);
IPAddress ip = IPAddress.Any;
//将IP地址和端口号绑定到网络节点point上
IPEndPoint ipe = new IPEndPoint(ip, port);
//定义一个套接字用于监听客户端发来的消息,包含三个参数(IP4寻址协议,流式连接,Tcp协议)
SocketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//监听绑定的网络节点
SocketWatch.Bind(ipe);
//将套接字的监听队列长度限制为20
SocketWatch.Listen(20);
//负责监听客户端的线程:创建一个监听线程
Thread threadwatch = new Thread(WatchConnecting);
//将窗体线程设置为与后台同步,随着主线程结束而结束
threadwatch.IsBackground = true;
//启动线程
threadwatch.Start();
Console.WriteLine("开启监听......");
Console.WriteLine("点击输入任意数据回车退出程序......");
Console.ReadKey();
SocketWatch.Close();
}
//监听客户端发来的请求
static void WatchConnecting()
{
Socket connection = null;
//持续不断监听客户端发来的请求
while (true)
{
try
{
connection = SocketWatch.Accept();
}
catch (Exception ex)
{
//提示套接字监听异常
Console.WriteLine(ex.Message);
break;
}
//客户端网络结点号
string remoteEndPoint = connection.RemoteEndPoint.ToString();
if(BlackClientConnectionItems.Keys.Any(n=>n==remoteEndPoint))
{
connection.Close();
break;
}
//添加客户端信息
ClientConnectionItems.Add(remoteEndPoint, connection);
//显示与客户端连接情况
Console.WriteLine("\r\n[客户端\"" + remoteEndPoint + "\"建立连接成功! 客户端数量:" + ClientConnectionItems.Count + "]");
//获取客户端的IP和端口号
IPAddress clientIP = (connection.RemoteEndPoint as IPEndPoint).Address;
int clientPort = (connection.RemoteEndPoint as IPEndPoint).Port;
//让客户显示"连接成功的"的信息
string sendmsg = "[" + "本地IP:" + clientIP + " 本地端口:" + clientPort.ToString() + " 连接服务端成功!]";
byte[] arrSendMsg = Encoding.UTF8.GetBytes(sendmsg);
connection.Send(arrSendMsg);
//创建一个通信线程
Thread thread = new Thread(recv);
//设置为后台线程,随着主线程退出而退出
thread.IsBackground = true;
//启动线程
thread.Start(connection);
//停1秒监测是否收到客户端信息
Thread.Sleep(2000);
//创建一个通信线程
Thread threadrec = new Thread(CloseConnect);
//设置为后台线程,随着主线程退出而退出
threadrec.IsBackground = true;
//启动线程
threadrec.Start(connection);
}
}
/// <summary>
/// 1秒后没有收到客户端信息就关闭连接
/// </summary>
/// <param name="socketclientpara"></param>
static void CloseConnect(object socketclientpara)
{
if(!IsRecvidData)
{
Socket socketServer = socketclientpara as Socket;
ClientConnectionItems.Remove(socketServer.RemoteEndPoint.ToString());
//提示套接字监听异常
Console.WriteLine("\r\n[客户端\"" + socketServer.RemoteEndPoint + "\"已经中断连接! 客户端数量:" + ClientConnectionItems.Count + "]");
//关闭之前accept出来的和客户端进行通信的套接字
socketServer.Close();
}
}
/// <summary>
/// 接收客户端发来的信息,客户端套接字对象
/// </summary>
/// <param name="socketclientpara"></param>
static void recv(object socketclientpara)
{
Socket socketServer = socketclientpara as Socket;
while (true)
{
//创建一个内存缓冲区,其大小为1024*1024字节 即1M
byte[] arrServerRecMsg = new byte[1024 * 1024];
//将接收到的信息存入到内存缓冲区,并返回其字节数组的长度
try
{
int length = socketServer.Receive(arrServerRecMsg);
//将机器接受到的字节数组转换为人可以读懂的字符串
string strSRecMsg = Encoding.UTF8.GetString(arrServerRecMsg, 0, length);
if(!string.IsNullOrWhiteSpace(strSRecMsg))
{
IsRecvidData = true;
}
string strDe = DESTool.DecryptDES(strSRecMsg, keyDe);
if(ReceiveStrList.Any(n=>n==strDe) ||strDe.Substring(0,28)!="*******2019"+ DateTime.Now.ToString("yyyyMMdd"))
{
//客户端网络结点号
string remoteEndPoint = socketServer.RemoteEndPoint.ToString();
BlackClientConnectionItems.Add(remoteEndPoint, socketServer);//加入黑名单
ClientConnectionItems.Remove(socketServer.RemoteEndPoint.ToString());
//提示套接字监听异常
Console.WriteLine("\r\n[客户端\"" + socketServer.RemoteEndPoint + "\"已经中断连接! 客户端数量:" + ClientConnectionItems.Count + "]");
//关闭之前accept出来的和客户端进行通信的套接字
socketServer.Close();
break;
}
//将发送的字符串信息附加到文本框txtMsg上
Console.WriteLine("\r\n[客户端:" + socketServer.RemoteEndPoint + " 时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + "]\r\n" + strDe.Substring(32, strDe.Length-32));
//Thread.Sleep(3000);
//socketServer.Send(Encoding.UTF8.GetBytes("[" + socketServer.RemoteEndPoint + "]:"+strSRecMsg));
//发送客户端数据
if (ClientConnectionItems.Count > 0)
{
foreach (var socketTemp in ClientConnectionItems)
{
socketTemp.Value.Send(Encoding.UTF8.GetBytes("[" + socketServer.RemoteEndPoint + "]:" + strSRecMsg));
}
}
}
catch (Exception ex)
{
if(ClientConnectionItems.Keys.Any(n=>n==socketServer.RemoteEndPoint.ToString()))
{
ClientConnectionItems.Remove(socketServer.RemoteEndPoint.ToString());
//提示套接字监听异常
Console.WriteLine("\r\n[客户端\"" + socketServer.RemoteEndPoint + "\"已经中断连接! 客户端数量:" + ClientConnectionItems.Count + "]");
//关闭之前accept出来的和客户端进行通信的套接字
socketServer.Close();
}
break;
}
}
}
}
}
加密工具类:DESTool
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace SocketServer
{
/// <summary>
/// DES对称加密和解密的工具类
/// </summary>
public class DESTool
{
/// <summary>
/// DES加密字符串
/// </summary>
/// <param name="encryptString">待加密的字符串</param>
/// <param name="encryptKey">加密密钥,要求为8位</param>
/// <returns>加密成功返回加密后的字符串,失败返回源串</returns>
public static string EncryptDES(string encryptString, string key)
{
try
{
byte[] rgbKey = Encoding.UTF8.GetBytes(key);
//用于对称算法的初始化向量(默认值)。
byte[] rgbIV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptString);
DESCryptoServiceProvider dCSP = new DESCryptoServiceProvider();
MemoryStream mStream = new MemoryStream();
CryptoStream cStream = new CryptoStream(mStream, dCSP.CreateEncryptor(rgbKey, rgbIV), CryptoStreamMode.Write);
cStream.Write(inputByteArray, 0, inputByteArray.Length);
cStream.FlushFinalBlock();
return Convert.ToBase64String(mStream.ToArray());
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// DES解密字符串
/// </summary>
/// <param name="decryptString">待解密的字符串</param>
/// <param name="key">解密密钥,要求8位</param>
/// <returns></returns>
public static string DecryptDES(string decryptString, string key)
{
try
{
//用于对称算法的初始化向量(默认值)
byte[] Keys = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
byte[] rgbKey = Encoding.UTF8.GetBytes(key);
byte[] rgbIV = Keys;
byte[] inputByteArray = Convert.FromBase64String(decryptString);
DESCryptoServiceProvider DCSP = new DESCryptoServiceProvider();
MemoryStream mStream = new MemoryStream();
CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateDecryptor(rgbKey, rgbIV), CryptoStreamMode.Write);
cStream.Write(inputByteArray, 0, inputByteArray.Length);
cStream.FlushFinalBlock();
return Encoding.UTF8.GetString(mStream.ToArray());
}
catch
{
return decryptString;
}
}
}
}
nlog.config文件
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<!--屏幕打印消息-->
<target name="console" xsi:type="ColoredConsole"
layout="${date:format=HH\:mm\:ss}> ${message}"/>
<!--VS输出窗口-->
<target name="debugger" xsi:type="Debugger"
layout="${date:format=HH\:mm\:ss} | ${level:padding=-5} | ${message}" />
<!--保存至文件-->
<target name="error_file" xsi:type="File" maxArchiveFiles="30"
fileName="${basedir}/Logs/Error/${shortdate}/error.txt"
layout="${longdate} | ${level:uppercase=false:padding=-5} | ${message} ${onexception:${exception:format=tostring} ${newline} ${stacktrace} ${newline}" />
</targets>
<rules>
<!--<logger name="*" writeTo="console" />-->
<logger name="*" minlevel="Debug" writeTo="debugger" />
<logger name="*" minlevel="Error" writeTo="error_file" />
</rules>
</nlog>
哪里不合理之处请多多指教,
源代码地址:https://download.youkuaiyun.com/download/it_ziliang/11434552