c# TCP/IP協議利用Socket的簡單通信


完全是基礎,新手可以隨意看看,大牛可以關閉瀏覽頁了,哈哈。

TCP/IP協議

TCP/IP是一系列網絡通信協議的統稱,其中最核心的兩個協議是TCP和IP。TCP稱為傳輸控制協議,IP稱為互聯網絡協議。

網絡分層除了OSI模型分層,還有TCP/IP模型分層,將網絡划分為四層,應用層、傳輸層、網際層、網絡接口層。TCP/IP模型分層是OSI模型分層的濃縮版

OSI模型和TCP/IP網絡分層的對應結構及TCP/IP部分協議族,

 

TCP三次握手

第一次握手:建立連接。客戶端發送連接請求報文段,將SYN位置為1,Sequence Number為x;然后,客戶端進入SYN_SEND狀態,等待服務器的確認;
第二次握手:服務器收到SYN報文段。服務器收到客戶端的SYN報文段,需要對這個SYN報文段進行確認,設置Acknowledgment Number為x+1(Sequence Number+1);同時,自己自己還要發送SYN請求信息,將SYN位置為1,Sequence Number為y;服務器端將上述所有信息放到一個報文段(即SYN+ACK報文段)中,一並發送給客戶端,此時服務器進入SYN_RECV狀態;
第三次握手:客戶端收到服務器的SYN+ACK報文段。然后將Acknowledgment Number設置為y+1,向服務器發送ACK報文段,這個報文段發送完畢以后,客戶端和服務器端都進入ESTABLISHED狀態,完成TCP三次握手。

三次握手圖解

在此基礎上,socket連接過程:

服務器監聽:服務器端socket並不定位具體的客戶端socket,而是處於等待監聽狀態,實時監控網絡狀態。

客戶端請求:客戶端clientSocket發送連接請求,目標是服務器的serverSocket。為此,clientSocket必須知道serverSocket的地址和端口號,進行掃描發出連接請求。

連接確認:當服務器socket監聽到或者是受到客戶端socket的連接請求時,服務器就響應客戶端的請求,建議一個新的socket,把服務器socket發送給客戶端,一旦客戶端確認連接,則連接建立。

注:在連接確認階段:服務器socket即使在和一個客戶端socket建立連接后,還在處於監聽狀態,仍然可以接收到其他客戶端的連接請求,這也是一對多產生的原因。

socket連接原理知道了,此處編寫最基本最簡單的socket通信:

客戶端代碼:

     /// <summary>
        /// 客戶端發送與服務端的連接請求,創建與之通信用的Socket
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnLink_Click(object sender, EventArgs e)
        {
            try
            {                   
          //定義一個用於請求連接服務器的IP和端口號
          IPEndPoint ip = new IPEndPoint(IPAddress.Parse(txtIp.Text), Convert.ToInt32(txtPort.Text));//txtIP:IP地址;txtPort:端口號
          //定義一個套接字用於請求連接服務器,包含三個參數(IP4尋址協議,流式連接,Tcp協議)
          socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

          //請求連接服務端 
          clientSocket.Connect(ip); 
          //創建一個通信線程,避免阻塞主線程 
          Thread th = new Thread(CRecive);
          //設置為后台線程,隨着主線程退出而退出
                th.IsBackground = true;
          //啟動線程
                th.Start(clientSocket);
          //顯示與服務端連接情況
                ShowMsg($"{clientSocket.RemoteEndPoint.ToString()}:已連接");
            }
            catch (Exception ex)
            {
          //提示套接字監聽異常
                ShowMsg($"網絡錯誤");
            }
        }

        /// <summary>
        /// 客戶端不停的接收服務端發送過來的消息
        /// </summary>
        /// <param name="o"></param>
        void CRecive(object o)
        {
            Socket socketSend = o as Socket;
            while (true)
            {
                try
                {
                    //創建一個內存緩沖區,其大小為1024*1024字節  即1M
                    byte[] buffer = new byte[1024 * 1024];
                    //將接收到的信息存入到內存緩沖區,並返回其字節數組的長度
                    int length = socketSend.Receive(buffer);
                    if (length == 0)
                    {
                        ShowMsg($"{socketSend.RemoteEndPoint.ToString()}:已斷開連接");
                        break;
                    }
            //將機器接受到的字節數組轉換為人可以讀懂的字符串
                    string str = Encoding.UTF8.GetString(buffer, 0, length);
            //將發送的字符串信息附加到ShowMsg上
                    ShowMsg($"Ta({socketSend.RemoteEndPoint.ToString()}):{str}");
                }
                catch (Exception ex)
                { }

            }
        } 

  

  客戶端向服務端發送數據:

clientSocket.Send(Encoding.UTF8.GetBytes($"{txtWrite.Text}"));

  

服務端代碼:

      /// <summary>
        /// 開啟監聽,等待客戶端連接
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnMonitor_Click(object sender, EventArgs e)
        {
            try
            {
                //定義一個套接字用於監聽客戶端發來的消息,包含三個參數(IP4尋址協議,流式連接,Tcp協議)
                socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //服務端發送信息需要一個IP地址和端口號
                IPAddress ip = IPAddress.Parse(txtIp.Text);//IPAddress.Any;
                                                           //將IP地址和端口號綁定到網絡節點point上
                IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text));
                //監聽綁定的網絡節點
                socketWatch.Bind(point);
                ShowMsg("開始監聽。。。");
                //將套接字的監聽隊列長度限制為10           
                socketWatch.Listen(10);
                //負責監聽客戶端的線程:創建一個監聽線程
                Thread th = new Thread(SListen);
                //將窗體線程設置為與后台同步,隨着主線程結束而結束
                th.IsBackground = true;
                //啟動線程
                th.Start(socketWatch);
            }
            catch (Exception ex)
            { }

        }
        /// <summary>
        /// 等待客戶端的連接 並且創建與之通信用的Socket
        /// </summary>
        /// <param name="o"></param>
        void SListen(object o)
        {
            Socket socketWatch = o as Socket;
            while (true)
            {
                try
                {
                    //等待客戶端的連接,並且創建與之通信用的Socket
                    Socket serverSocket = socketWatch.Accept();
                    //獲取客戶端網絡結點號
                    string socketIP = serverSocket.RemoteEndPoint.ToString();
                    ShowMsg($"{socketIP}:已連接");
                    //創建一個通信線程,避免阻塞主線程
                    Thread th = new Thread(SRecive);
                    th.IsBackground = true;
                    th.Start(serverSocket);
                }
                catch
                { }
            }
        }
        /// <summary>
        /// 服務端不停的接收客戶端發送過來的消息
        /// </summary>
        /// <param name="o"></param>
        void SRecive(object o)
        {
            Socket socketSend = o as Socket;
            while (true)
            {
                //將接收到的信息存入到內存緩沖區,並返回其字節數組的長度
                try
                {
                    //創建一個內存緩沖區,其大小為1024*1024字節  即1M
                    byte[] buffer = new byte[1024 * 1024];
                    //接收客戶端發送過來的消息
                    int length = socketSend.Receive(buffer);
                    if (length == 0)
                    {
                        ShowMsg($"{socketSend.RemoteEndPoint.ToString()}:已斷開連接");
                        break;
                    }
                    //將機器接受到的字節數組轉換為人可以讀懂的字符串
                    string str = Encoding.UTF8.GetString(buffer, 0, length);
                    //將發送的字符串信息附加到ShowMsg上
                    ShowMsg($"Ta({socketSend.RemoteEndPoint.ToString()}):{str}");
                }
                catch (Exception ex) { }
            }
        }    

  

  

 服務端向已連接的客戶端發送數據: 

serverSocket.Send(Encoding.UTF8.GetBytes($"{txtWrite.Text}"));

  

  注:c#新手的隨手筆記,方便以后學習和使用,如有不足和雷同,歡迎留言!謝謝!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM