2011-04-27 60 views
1

我正在構建一個IRC客戶端,並且需要一個IRC獨立網絡類,它只是在客戶端和服務器之間發送和接收線路。發送行是確定的,但是我不知道如何實現一個監聽器線程。我嘗試過的所有方法都有效,但有缺陷,我無法解決。什麼是實施基於行的網絡工作者類的正確方法

我的第一個方法是創建一個StreamReader使用TcpClient.GetStream()爲基礎,只是在做一個叫_reader.ReadLine()_reader。這樣做的好處是後臺偵聽器線程會自動停止,直到收到一條線。問題是,當我斷開和停止監聽器線程(或應用程序剛剛退出)時,我不確定它有多好,因爲垃圾回收等,線程等待ReadLine()只是被殺死。該線程是否會成爲孤兒,並以某種方式留在後臺竊取資源?

我的第二個方法是創建基於相同TcpClient.GetStream()一個NetworkStream_reader,並創建一個循環,檢查_reader.DataAvailablecontinue while循環,如果是假的,否則按字節到被立即檢查\r\n一個StringBuilder並提取任何整行。這與ReadLine在數據檢索方面的效果相同,但我不喜歡常量_reader.DataAvailable循環。在我的酷睿i5 CPU上,它不需要任何CPU,但是在我的功能更強大的i9筆記本電腦上,它不斷竊取虛擬CPU。 Thread.Sleep(1)「解決」了這一點,但似乎是一個骯髒的修復,並在互聯網上的許多文章將此分類爲代碼味道。

那麼適當的解決方案是什麼?

回答

1

如果你正在中止監聽線程,那很糟糕。但是,如果應用程序退出(或者關閉底層套接字),那麼它會很好。

列出大多數人,我不推薦投票。我會建議使用異步讀取和寫入的解決方案,但編程起來要困難得多。

+0

我已經看過異步方法,但MSDN文檔 - 尤其是示例代碼 - 充滿了缺陷和錯誤。我還沒有找到一個很好的指導如何使用它們。 – carlsb3rg 2011-04-27 18:43:31

+0

是的。最有用的資源是非託管TCP/IP應用程序。我在[常見問題](http://nitoprograms.blogspot.com/2009/04/tcpip-net-sockets-faq.html)的第2部分有一些指導原則,但它不是教程級材料。 – 2011-04-27 18:57:50

+0

我從不放棄線程。這是後臺線程在應用程序關閉時自動死亡。偵聽循環是'while(tcpClient.Connected){...}'。如果我使用'.ReadLine()',那麼就沒有辦法強制程序繼續執行下一個'while'檢查並優雅地結束循環。這就是爲什麼我想使用NetworkStream方法,因爲我可以在數據不可用時連續循環,並在需要時正常退出。我喜歡你的常見問題。你應該避開常見的FAQ條目。 – carlsb3rg 2011-04-27 20:57:30

0

這是讓你去的東西。

請注意,構建消息時使用string效率不高。但它使一切更具可讀性。

public abstract class LineBasedChannel 
{ 
    Socket _socket; 
    string _inbuffer = string.Empty; 
    Encoding _encoding; 
    byte[] _buffer = new byte[8192]; 

    public LineBasedChannel(Socket socket) 
    { 
     _socket = socket; 
     _encoding = Encoding.ASCII; 
     _sb = new StringBuilder(); 
    } 

    public void Start() 
    { 
     _socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None,OnRead, null); 
    } 

    public void OnRead(IAsyncResult res) 
    { 
     var bytesRead = _socket.EndReceive(res); 
     if (bytesRead == 0) 
     { 
      HandleDisconnect(); 
      return; 
     } 

     _inbuffer += _encoding.GetString(_buffer, 0, bytesRead); 
     _socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None,OnRead, null); 

     while (true) 
     { 
      int pos = _inbuffer.IndexOf("\r\n"); 
      if (pos == -1) 
       break; 

      OnReceivedLine(_inbuffer.SubString(0, pos+2); 
      _inbuffer = _inbuffer.Remove(0,pos+1); 
     } 
    } 

    protected abstract void OnReceivedLine(string line); 
} 

public class IrcTcpChannel : LineBasedChannel 
{ 
    protected override void OnReceivedLine(string line) 
    { 
     var cmd = new IrcCommand(); 
     cmd.Channel = line.SubString(x,y); 
     cmd.Message = line.SubString(z,a); 
     CommandReceived(this, new IrcCommandEventArgs(cmd)); 
    } 

    public event EventHandler<IrcCommandEventArgs> CommandReceived = delegate {}; 
} 

另請注意,我沒有處理該代碼中的任何異常,這是強制性的。異步方法中的任何未處理的異常將終止您的應用程序。

0

老問題,這個問題早就定下來了。無論如何,它看起來非常像舊的問題c# - What is a good method to handle line based network I/O streams? - Stack Overflow

如果是這樣,那麼答案應該提供部分解決方案。基本上,這是一個類,它提供了一個返回IEnumerable<string>Process(byte[])方法,該方法保持部分內容的狀態尚未形成完整行。

使用這將允許分開關注。只讀數據,因爲它是可用的。每次讀取塊時,都會將它饋送到該方法中,因爲它們完全形成時會出現線條。

相關問題