SocketServer通信服務端,加密通信,記錄IP地址,黑名單,白名單,首次不發送消息就加入黑名單

    什麼是 socket?

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章