c#Socket通信實例


        在上一篇文章中介紹了Socket基礎—TCP與UDP協議和他們之間的區別,這篇文章參考另一位前輩的博文重點記錄下Socket的原理及兩種協議的開發過程。

一、Socket通信簡介

 1.按慣例先來介紹下socket

        Windows中的很多東西都是從Unix領域借鑒過來的,Socket也是一樣。在Unix中,socket代表了一種文件描述符(在Unix中一切都是以文件為單位),而這里這個描述符則是用於描述網絡訪問的。什么意思呢?就是程序員可以通過socket來發送和接收網絡上的數據。你也可以理解成是一個API。有了它,你就不用直接去操作網卡了,而是通過這個接口,這樣就省了很多復雜的操作。
在C#中,MS為我們提供了 System.Net.Sockets 命名空間,里面包含了Socket類。

2.有了socket,那就可以用它來訪問網絡了

      不過你不要高興得太早,要想訪問網絡,還得有些基本的條件(和編程無關的我就不提了):a. 要確定本機的IP和端口,socket只有與某一IP和端口綁定,才能發揮強大的威力。b. 得有協議吧(否則誰認得你這發送到網絡的是什么呀)。想要復雜的,我們可以自己來定協議。但是這個就不在這篇里提了,我這里介紹兩種大家最熟悉不過的協議:TCP & UDP。(別說你不知道,不然...不然...我不告訴你)
如果具備了基本的條件,就可以開始用它們訪問網絡了。來看看步驟吧:
a. 建立一個套接字
b. 綁定本機的IP和端口
c. 如果是TCP,因為是面向連接的,所以要利用Listen()方法來監聽網絡上是否有人給自己發東西;如果是UDP,因為是無連接的,所以來者不拒。
d. TCP情況下,如果監聽到一個連接,就可以使用accept來接收這個連接,然后就可以利用Send/Receive來執行操作了。而UDP,則不需要accept, 直接使用SendTo/ReceiveFrom來執行操作。(看清楚哦,和TCP的執行方法有區別,因為UDP不需要建立連接,所以在發送前並不知道對方的IP和端口,因此需要指定一個發送的節點才能進行正常的發送和接收)
e. 如果你不想繼續發送和接收了,就不要浪費資源了。能close的就close吧。

   面向連接的套接字系統調用時序 (TCP)

    

 無連接的套接字系統調用時序(UDP)

 

二、TCP協議的Socket實例

服務端 后台代碼:

  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Data;
  5 using System.Drawing;
  6 using System.IO;
  7 using System.Linq;
  8 using System.Net;
  9 using System.Net.Sockets;
 10 using System.Text;
 11 using System.Threading;
 12 using System.Threading.Tasks;
 13 using System.Windows.Forms;
 14 
 15 namespace Socket通信
 16 {
 17     public partial class Form1 : Form
 18     {
 19 
 20         public Form1()
 21         {
 22             InitializeComponent();
 23             TextBox.CheckForIllegalCrossThreadCalls = false;
 24 
 25         }
 26         Socket socketSend;
 27         Thread threadWatch = null; // 負責監聽客戶端連接請求的 線程;
 28         Socket socketWatch = null;
 29 
 30 
 31         /// <summary>
 32         /// 監聽客戶端請求的方法;
 33         /// </summary>
 34         void WatchConnecting()
 35         {
 36             try
 37             {
 38                 while (true)  // 持續不斷的監聽客戶端的連接請求;
 39                 {
 40                     // 開始監聽客戶端連接請求,Accept方法會阻斷當前的線程;
 41                     Socket sokConnection = socketWatch.Accept(); 
 42                     // 一旦監聽到一個客戶端的請求,就返回一個與該客戶端通信的 套接字;
 43                     // 向列表控件中添加客戶端的IP信息;
 44                     lbOnline.Items.Add(sokConnection.RemoteEndPoint.ToString());
 45                     ShowMsg("客戶端連接成功!");
 46                     //開啟一個新線程,執行接收消息方法
 47                     Thread r_thread = new Thread(Received);
 48                     r_thread.IsBackground = true;
 49                     r_thread.Start(sokConnection);
 50                 }
 51             }
 52             catch (Exception e)
 53             {
 54                 ShowMsg("異常:" + e.Message);
 55             }
 56 
 57         }
 58         /// <summary>
 59         /// 服務器端不停的接收客戶端發來的消息
 60         /// </summary>
 61         /// <param name="o"></param>
 62         void Received(object o)
 63         {
 64             try
 65             {
 66                  socketSend = o as Socket;
 67                 while (true)
 68                 {
 69                     //客戶端連接服務器成功后,服務器接收客戶端發送的消息
 70                     // 定義一個3M的緩存區;
 71                     byte[] buffer = new byte[1024 * 1024 * 3];
 72                     //實際接收到的有效字節數
 73                     // 將接受到的數據存入到輸入  buffer中;
 74                     int len = socketSend.Receive(buffer);
 75                     if (len == 0)
 76                     {
 77                         break;
 78                     }
 79                     string str = Encoding.UTF8.GetString(buffer, 0, len);
 80                     ShowMsg("接收到的客戶端數據:" + socketSend.RemoteEndPoint + ":" + str);
 81                     Send("服務端接收成功(" + str + "");
 82 
 83                 }
 84             }
 85             catch (Exception e)
 86             {
 87                 ShowMsg("異常:" + e.Message);
 88             }
 89         }
 90         /// <summary>
 91         /// 服務器向客戶端發送消息
 92         /// </summary>
 93         /// <param name="str"></param>
 94         void Send(string str)
 95         {
 96             byte[] buffer = Encoding.UTF8.GetBytes(str);
 97             socketSend.Send(buffer);
 98 
 99         }
100         void ShowMsg(string str)
101         {
102             txtMsg.AppendText(str + "\r\n");
103         }
104         private void button1_Click_1(object sender, EventArgs e)
105         {
106             // 創建負責監聽的套接字,注意其中的參數;
107             socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
108             // 獲得文本框中的IP對象;
109             IPAddress address = IPAddress.Parse(txtIp.Text.Trim());
110             // 創建包含ip和端口號的網絡節點對象;
111             IPEndPoint endPoint = new IPEndPoint(address, int.Parse(txtPort.Text.Trim()));
112             try
113             {
114                 // 將負責監聽的套接字綁定到唯一的ip和端口上;
115                 socketWatch.Bind(endPoint);
116             }
117             catch (SocketException se)
118             {
119                 MessageBox.Show("異常:" + se.Message);
120                 return;
121             }
122             // 設置監聽隊列的長度;
123             socketWatch.Listen(10);
124             // 創建負責監聽的線程;
125             threadWatch = new Thread(WatchConnecting);
126             threadWatch.IsBackground = true;
127             threadWatch.Start();
128             ShowMsg("服務器啟動監聽成功!");
129         }
130     }
131 }
Socket_server

客戶端 后台代碼:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.ComponentModel;
 4 using System.Data;
 5 using System.Drawing;
 6 using System.Linq;
 7 using System.Text;
 8 using System.Threading.Tasks;
 9 using System.Windows.Forms;
10 using System.Net;
11 using System.Net.Sockets;
12 using System.Threading;
13 
14 
15 namespace Socket通信客戶端
16 {
17     public partial class Socket_client : Form
18     {
19         public Socket_client()
20         {
21             InitializeComponent();
22             CheckForIllegalCrossThreadCalls = false;
23         }
24         Socket socketSend;
25         void ShowMsg(string str)
26         {
27             txtMsg.AppendText(str + "\r\n");
28         }
29         /// <summary>
30         /// 接收服務端返回的消息
31         /// </summary>
32         void Received()
33         {
34             while (true)
35             {
36                 try
37                 {
38                     byte[] buffer = new byte[1024 * 1024 * 3];
39                     //實際接收到的有效字節數
40                     int len = socketSend.Receive(buffer);
41                     if (len == 0)
42                     {
43                         continue;
44                     }
45                     string str = Encoding.UTF8.GetString(buffer, 0, len);
46                     ShowMsg("接收到的服務端數據:" + socketSend.RemoteEndPoint + ":" + str);
47                 }
48                 catch
49                 {
50                     MessageBox.Show("接收失敗,請檢查服務端是否斷開!");
51                     return;
52                 }
53             }
54         }
55 
56         private void btnDisconnect_Click(object sender, EventArgs e)
57         {
58             socketSend.Close();
59             ShowMsg("連接已經斷開!");
60         }
61         void Send(string str)
62         {
63             byte[] buffer = Encoding.UTF8.GetBytes(str);
64             socketSend.Send(buffer);
65         }
66     }
67 }
Socket_client

三、UDP協議的Socket實例

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace SimpleUdpSrvr
{
    class Program
    {
        static void Main(string[] args)
        {
            int recv;
            byte[] data = new byte[1024];
            IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050);//定義一網絡端點
            Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);//定義一個Socket
            newsock.Bind(ipep);//Socket與本地的一個終結點相關聯
            Console.WriteLine("Waiting for a client..");

            IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);//定義要發送的計算機的地址
            EndPoint Remote = (EndPoint)(sender);//
            recv = newsock.ReceiveFrom(data, ref Remote);//接受數據           
            Console.WriteLine("Message received from{0}:", Remote.ToString());
            Console.WriteLine(Encoding.ASCII.GetBytes(data,0,recv));

            string welcome = "Welcome to my test server!";
            data = Encoding.ASCII.GetBytes(welcome);
            newsock.SendTo(data, data.Length, SocketFlags.None, Remote);
            while (true)
            {
                data = new byte[1024];
                recv = newsock.ReceiveFrom(data, ref Remote);
                Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));
                newsock.SendTo(data, recv, SocketFlags.None, Remote);
            }
        }
    }
}
UDPServer
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace SimpleUdpClient
{
    class Program
    {
        static void Main(string[] args)
        {
            byte[] data = new byte[1024];//定義一個數組用來做數據的緩沖區
            string input, stringData;
            IPEndPoint ipep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9050);
            Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            string welcome = "Hello,are you there?";
            data = Encoding.ASCII.GetBytes(welcome);
            server.SendTo(data, data.Length, SocketFlags.None, ipep);//將數據發送到指定的終結點

            IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
            EndPoint Remote = (EndPoint)sender;
            data = new byte[1024];
            int recv = server.ReceiveFrom(data, ref Remote);//接受來自服務器的數據

            Console.WriteLine("Message received from{0}:", Remote.ToString());
            Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));
            while (true)//讀取數據
            {
                input = Console.ReadLine();//從鍵盤讀取數據
                if (input == "text")//結束標記
                {
                    break;
                }
                server.SendTo(Encoding.ASCII.GetBytes(input), Remote);//將數據發送到指定的終結點Remote
                data = new byte[1024];
                recv = server.ReceiveFrom(data, ref Remote);//從Remote接受數據
                stringData = Encoding.ASCII.GetString(data, 0, recv);
                Console.WriteLine(stringData);
            }
            Console.WriteLine("Stopping client");
            server.Close();
        }
    }
}     
UDPClient

   上面的示例只是簡單的應用了socket來實現通信,你也可以實現異步socket、IP組播 等等。

     MS還為我們提供了幾個助手類:TcpClient類、TcpListener類、UDPClient類。這幾個類簡化了一些操作,所以你也可以利用這幾類來寫上面的代碼,但我個人還是比較習慣直接用socket來寫。
      既然快寫完了,那我就再多啰嗦幾句。在需要即時響應的軟件中,我個人更傾向使用UDP來實現通信,因為相比TCP來說,UDP占用更少的資源,且響應速度快,延時低。至於UDP的可靠性,則可以通過在應用層加以控制來滿足。當然如果可靠性要求高的環境下,還是建議使用TCP。


免責聲明!

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



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