.NET Socket開發之同步Socket實現兩例

.NET Socket開發之同步Socket實現兩例
今天,我們來講一下在.NET 網絡應用程序開發中同步Socket的應用,很多人認爲在網絡應用的服務端Socket不應該使用同步Socket。是的,在大多數情況下是這樣的,但是 也有一些場景下我們使用同步Socket可能會得到更的結果。如在下面的兩種場景下我們便可以考慮使用同步的Socket。
一、客戶端數量比較少:
數量比較少是指會同時連接到服務器的客戶端數量一般在50人以下。這種情況下我們可以考慮使用同步Socket+Thread來實現我們的服務端。這樣會讓我們編寫邏輯更清晰的代碼而性能不會下降太多。
二、客戶端數量較多但都是短連接:
短連接是指客戶端的連接在處理完一次收發之後就產即斷開的場景,比如說HTTP協議就 是一種短連接。HTTP在客戶端發出請求時建立一個Socket連接,並通過Socket發出一個URL請求,服務端在處理完這個請求並回發相應的頁面後 便會斷開這個連接。那麼在這種場景下我們也可以使用同步Socket來實現我們的需求。
那麼應該如果實現我上面提到的兩種需求呢。對於這兩種需求,我將採用不同的方案來實現它們。
首先我們來看看第一種需求,這裏我採用Socket+Thread來實現,基本的流程如下:
首先創建一個Socket,並且給它綁定一個EndPoint後開始監聽。接下來我們 創建一個線程,在這個線程中我們用一個無限循環來接收來自客戶端的連接請求。在接收到一個請求後,爲這個客戶端創建一個新的線程,並且在這個線程中也使用 一個無限循環接收來自這個客戶端的數據。下面讓我們來看看代碼:
 
首先我們創建一個Socket用來偵聽客戶端的連接:
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint locEP
= new IPEndPoint(IPAddress.Any, 2000);
listener.Bind(locEP);
listener.Listen(
100);
然後創建一個線程來處理客戶端的連接請求:
Thread acceptThread = new Thread(new ThreadStart(AcceptWorkThread));
acceptThread.Start();
 
private void AcceptWorkThread()
{
    Thread.CurrentThread.IsBackground 
= true;
    
while (true)
    
{
        Socket accept 
= listener.Accept();
        IPEndPoint remoEP 
= (IPEndPoint)accept.RemoteEndPoint;
        
string recString = "接收到來自" + remoEP.Address.ToString() + "的連接。";
        
this.Invoke(new AddListItemHandler(this.AddListItem), new string[] { recString });
        Thread receiveThread 
= new Thread(new ParameterizedThreadStart(ReceiveWorkThread));
        receiveThread.Start(accept);
    }

}
最後我們來看看如何接收數據:
private void ReceiveWorkThread(object obj)
{
    Thread.CurrentThread.IsBackground 
= true;
    Socket socket 
= (Socket)obj;
    
byte[] buffer = new byte[1024];
    
while (true)
    
{
        
int receiveCount = socket.Receive(buffer);
        
if (receiveCount > 0)
        
{
            IPEndPoint remoEP 
= (IPEndPoint)socket.RemoteEndPoint;
            
string recString = "來自客戶端" + remoEP.Address.ToString() + "的消息:" + Encoding.Default.GetString(buffer, 0, receiveCount);
            
this.Invoke(new AddListItemHandler(this.AddListItem), new string[] { recString });
            socket.Send(buffer, receiveCount, SocketFlags.None);
        }

        
else
        
{
            socket.Close();
            
break;
        }

    }

}
好了,整個實現就完成了。
現在讓我們來看看第二個需求:
這個方案我們將採用另外一個方法來實現,爲什麼不採用上一個方法來實現呢?讓我們來分 析一下。我們知道,在上一個實現中,每接入一個客戶端就要創建一個線程,如果有大量的客戶端接入的話,就會創建過多的線程。但是如果線程過多的話, Windows就需要更多的CPU時間來切換線程的上下文(這也是上一個實現不能接入很多客戶端的原因)。
我們知道,在這個方案中每一個連接都是短連接。而且順序都是固定的。都是:接入->接收->發送這樣的順序,那麼我們就可以在一個方法中完成整個處理。這樣,我們就可以利用線程池來實現我們所需要的。好了,讓我們用代碼來說話吧:
 
首先我們創建一個Socket用來偵聽客戶端的連接:
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint locEP
= new IPEndPoint(IPAddress.Any, 2000);
listener.Bind(locEP);
listener.Listen(
100);
接下來我們要創建一個線程池:
Thread[] ClientThreadList = new Thread[30];
foreach (Thread th in ClientThreadList)
{
    th 
= new Thread(new ThreadStart(ClientWorkThread));
    th.Start();
}
最後讓我們看看線程都要做些什麼:
private void ClientWorkThread()
{
    
byte[] buffer = new byte[1024];
    
while (true)
    
{
        Socket socket 
= listener.Accept();
        
string recString = "接收到來自" + remoEP.Address.ToString() + "的連接。";
        
this.Invoke(new AddListItemHandler(this.AddListItem), new string[] { recString });
        
int receCount = socket.Receive(buffer);
        
if (receCount>0)
        
{
            
string recString = "來自客戶端" + remoEP.Address.ToString() + "的消息:" + Encoding.Default.GetString(buffer, 0, receiveCount);
            
this.Invoke(new AddListItemHandler(this.AddListItem), new string[] { recString });
            socket.Send(buffer, receCount, SocketFlags.None);
        }

        socket.Shutdown(SocketShutdown.Both);
        socket.Close();
    }

}
爲什麼我們要這樣做呢?
首先我們創建了一個Socket用於偵聽客戶端的連接請求,接下我們創建了一個擁有30個線程的線程池。並在每個線程中實現了Accept、Receive、Send和Close(),以完成連接、接收、發送、關閉的操作。
現在我們假設有一個客戶連接到服務器了,這時會有一個線程Accept到這個請求,並開始接收客戶端發送過來的數據,接收到數據之後處理完髮送給客戶端,然後關閉這個連接,再次進入等待連接狀態。而其它29個線程由於沒有Accept到這個請求,仍然處理等待接入狀態。
相信現在大家都看明白了吧,如果還有不明白的地方,歡迎大家來聯繫我:
我的QQ:6570858;MSN:[email protected];電子郵箱:[email protected]
 
發佈了38 篇原創文章 · 獲贊 4 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章