1

IRC クライアントを作成していますが、クライアントとサーバーの間で回線を送受信するだけの IRC に依存しないネットワーク クラスが必要です。回線を送信することは問題ありませんが、リスナー スレッドを実装する良い方法が見つからないのです。私が試したすべての方法は機能しますが、回避できない欠点があります。

私の最初の方法は、ベースとして使用してStreamReader呼び出されたを作成し、 . これには、回線が受信されるまでバックグラウンド リスナー スレッドが自動的に停止するという利点があります。問題は、リスナー スレッドを切断して停止する (またはアプリケーションが終了する) ときに、待機中のスレッドが強制終了されるだけで、ガベージ コレクションなどにどの程度適しているかがわからないことです。スレッドが孤立して、リソースを盗んでバックグラウンドにとどまる可能性はありますか?_readerTcpClient.GetStream()_reader.ReadLine()ReadLine()

私の 2 番目の方法は、同じ に基づいてNetworkStream呼び出された を作成し、false の場合は while ループをチェックするループを作成し、それ以外の場合はバイトを StringBuilder にプッシュし、即座にチェックして行全体を抽出することでした。これにより、データの取得時に ReadLine と同じ効果が得られますが、一定のループが好きではありません。私の Core i5 CPU では、CPU を必要としませんが、より強力な i9 ラップトップでは、常に仮想 CPU を盗みます。これを「解決」しますが、汚い修正のように見え、インターネット上の多数の記事がこれをコードの匂いとして分類しています。_readerTcpClient.GetStream()_reader.DataAvailablecontinue\r\n_reader.DataAvailableThread.Sleep(1)

では、適切な解決策は何でしょうか?

4

3 に答える 3

1

リスナースレッドを中止する場合、それは悪いことです。ただし、アプリケーションが終了した場合(または、基になるソケットを閉じた場合)は、問題ありません。

他のほとんどをリストしてください、私はポーリングをお勧めしません。プログラミングははるかに困難ですが、非同期の読み取りと書き込みを使用するソリューションをお勧めします。

于 2011-04-27T16:56:36.817 に答える
0

古い質問ですが、問題はずっと前に解決したに違いありません。とにかく、それはさらに古い質問c# - ラインベースのネットワーク I/O ストリームを処理するための良い方法は何ですか? と非常によく似ています。- スタックオーバーフロー

もしそうなら、そこにある答えは解決策の一部を提供するはずです。基本的には、完全な行を形成していない部分的なコンテンツの状態を保持 Process(byte[])する を返すメソッドを提供するクラスです。IEnumerable<string>

それを使用すると、懸念事項を分離できます。利用可能なデータを読み取るだけです。チャンクが読み取られるたびに、そのメソッドにフィードすると、完全に形成された行が取得されます。

于 2015-08-19T08:40:17.813 に答える
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 {};
}

また、そのコードでは例外を処理していないことに注意してください。これは必須です。非同期メソッドで未処理の例外が発生すると、アプリケーションが終了します。

于 2011-04-29T13:09:42.507 に答える