什麼是 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.csdn.net/download/it_ziliang/11434552