C# Socket詳細剖析
C#語言還是比較常見的東西,這里我們主要介紹C# Socket,包括介紹建立本機的IPEndPoint對象等方面。
其實只要用到Socket聯接,基本上就得使用Thread,是交叉使用的。C# Socket用法基本上不算很復雜,只是不知道托管之后的Socket有沒有其他性能或者安全上的問題。在C#里面能找到的***層的操作也就是socket了,概念不做解釋。
程序模型如下:
◆WinForm程序 : 啟動端口偵聽;監視Socket聯接情況;定期關閉不活動的聯接;
◆Listener:處理Socket的Accept函數,偵聽新鏈接,建立新Thread來處理這些聯接(Connection)。
◆Connection:處理具體的每一個聯接的會話。
1:WinForm如何啟動一個新的線程來啟動Listener:
- //start the server
- private void btn_startServer_Click(object sender, EventArgs e)
- {
- //this.btn_startServer.Enabled = false;
- Thread _createServer = new Thread(new ThreadStart(WaitForConnect));
- _createServer.Start();
- }
- //wait all connections
- private void WaitForConnect()
- {
- SocketListener listener = new SocketListener(Convert.ToInt32(this.txt_port.Text));
- listener.StartListening();
- }
因為偵聽聯接是一個循環等待的函數,所以不可能在WinForm的線程里面直接執行,不然Winform也就是無法繼續任何操作了,所以才指定一個新的線程來執行這個函數,啟動偵聽循環。
這一個新的線程是比較簡單的,基本上沒有啟動的參數,直接指定處理函數就可以了。
2:Listener如何啟動循環偵聽,并且啟動新的帶有參數的線程來處理Socket聯接會話。
先看如何建立偵聽:(StartListening函數)
- // Create a TCP/IP socket.
- Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- // Bind the socket to the local endpoint andlisten for incoming connections.
- try
- {
- listener.Bind(localEndPoint);
- listener.Listen(20);//20 trucks
- // Start listening for connections.
- while (true)
- {
- // here will be suspended while waiting for a new connection.
- Socket connection = listener.Accept();
- Logger.Log("Connect", connection.RemoteEndPoint.ToString());//log it, new connection
- ……
- }
- }
- ……
基本步驟比較簡單:
建立本機的IPEndPoint對象,表示以本機為服務器,在指定端口偵聽;然后綁定到一個偵聽Socket上;進入while循環,等待新的聯接;如果有新的聯接,那么建立新的socket來對應這個聯接的會話。
值得注意的就是這一句聯接代碼:listener.Accept()。執行這一句的時候,程序就在這個地方等待,直到有新的聯檢請求的時候程序才會執行下一句。這是同步執行,當然也可以異步執行。
新的聯接Socket建立了(Accept之后),對于這些新的socket該怎么辦呢?他們依然是一個循環等待,所以依然需要建立新的Thread給這些Socket去處理會話(接收/發送消息),而這個Thread就要接收參數了。Thread本身是不能接收參數的,為了讓它可以接收參數,可以采用定義新類,添加參數作為屬性的方法來解決。因為每一個Socket是一個Connection周期,所以我定義了這么一個類public class Connection。這個類至少有這樣一個構造函數public Connection(Socket socket); 之所以這么做,就是為了把Socket參數傳給這個Connection對象,然后好讓Listener啟動這個Thread的時候,Thread可以知道他正在處理哪一個Socket。具體處理的方法:(在Listener的StartListening函數,ocket connection = listener.Accept();之后)
- Connection gpsCn = new Connection(connection);
- //each socket will be wait for data. keep the connection.
- Thread thread = new Thread(new ThreadStart(gpsCn.WaitForSendData));
- thread.Name = connection.RemoteEndPoint.ToString();
- thread.Start();
3:Connection的會話處理
建立了新的Connection(也就是socket),遠程就可以和這個socket進行會話了,無非就是send和receive。現在先看看怎么寫的這個線程運行的Connection. WaitForSendData函數
- while (true)
- {
- bytes = new byte[1024];
- string data = "";
- //systm will be waiting the msg of receive envet. like Accept();
- //here will be suspended while waiting for socket income msg.
- int bytesRec = this._connection.Receive(bytes);
- _lastConnectTime = DateTime.Now;
- if (bytesRec == 0)//close envent
- {
- Logger.Log("Close Connection", _connection.RemoteEndPoint.ToString());
- break;
- }
- data += Encoding.ASCII.GetString(bytes, 0, bytesRec);
- //…….handle your data.
- }
可以看到這個處理的基本步驟如下:執行Receive函數,接收遠程socket發送的信息;把信息從字節轉換到string;處理該信息,然后進入下一個循環,繼續等待C# Socket發送新的信息。
值得注意的有幾個:
1:Receive函數。這個函數和Listener的Accept函數類似。在這個地方等待執行,如果沒有新的消息,這個函數就不會執行下一句,一直等待。
2:接收的是字節流,需要轉化成字符串
3:判斷遠程關閉聯接的方式
4:如果對方的消息非常大,還得循環接收這個data。
【編輯推薦】