3

マルチスレッドおよびソケット消費との互換性に関して、System.Net.WebRequestおよびSystem.Net.HttpRequestで問題が発生しました。私はレベルを下げて、自分のダートシンプルなHttpクラスをロールバックしようとしました。

以前の問題は、各スレッドがあまりにも多くのソケットを作成するのが速すぎることだったので、複数の反復(forループ)で単一のソケット(スレッドごとに1つ)を使用しようとしています。

コード:

私のテストクラス(動作するまでIPとポートをハードコーディングしています):

public sealed class Foo : IDisposable {

        private string m_ip = "localhost";
        private int m_port = 52395;
        private TcpClient m_tcpClient;


        public Foo() {
            m_tcpClient = new TcpClient( m_ip, m_port );
        }

        public void Execute() {
            using( var stream = m_tcpClient.GetStream() )
            using( var writer = new StreamWriter( stream ) )
            using( var reader = new StreamReader( stream ) ) {
                writer.AutoFlush = true;
                // Send request headers
                writer.WriteLine( "GET /File HTTP/1.1" );
                writer.WriteLine( "Host: " + m_ip + ":" + m_port.ToString() );
                writer.WriteLine( "Connection: Keep-Alive" );
                writer.WriteLine();
                writer.WriteLine();

                // Read the response from server
                string response = reader.ReadToEnd();
                Console.WriteLine( response );
            }
        }    

        void IDisposable.Dispose() {
            m_tcpClient.Client.Dispose();
        }
    }

静的ボイドメイン:

using( Foo foo = new Foo() ) {
    for( int i = 0; i < 10; i++ ) {
        foo.Execute();
    }
}

エラー

私が受け取っているエラーThe operation is not allowed on non-connected sockets.は、forループの最初の反復が正常に完了した後です。

エラーの原因は理解できますが(応答を読み取った後はTcpClient.Client閉じます)、ソケットに開いたままにするように明示的に指示する方法がわかりません。

編集 サーバーにあるサーバーから返されるHTTP応答の詳細な調査Connection: Close。これは生のTCPであるため、HTTPを解析しないと思いました。これが問題の原因でしょうか?(もしそうなら、それを無視する方法があります)

4

3 に答える 3

2

mainメソッドの順序を変更して、反復ごとに新しいオブジェクトを作成するようにします

for( int i = 0; i < 10; i++ ) 
{
    using( Foo foo = new Foo() ) 
    {
        foo.Execute();
    }
}

ソケットを開いたままにしておきたい場合は、アプリケーションを少しリファクタリングしてDispose、たとえば1回の反復後に呼び出されないようにする必要があります。

public sealed class Foo : IDisposable {    
    private string m_ip = "localhost";
    private int m_port = 52395;
    private TcpClient m_tcpClient;

    private Stream stream;
    private StreamWriter writer;
    private StreamReader reader;

    public void Execute() {         
        // Send request headers
            ...    
        // Read the response from server                
    }   

    void Open(){
        m_tcpClient = new TcpClient( m_ip, m_port );
        stream = m_tcpClient.GetStream();
        writer = new StreamWriter( stream );
        reader = new StreamReader( stream );
    }   

    void Close() {
        m_tcpClient.Client.Dispose();
        reader.Dispose();
        writer.Dispose();
        stream.Dispose();
    }

    //Plus Dispose implementation
}

そしてここに使用法があります

using( Foo foo = new Foo() ) {
    foo.Open();
    for( int i = 0; i < 10; i++ ) {
        foo.Execute();
    }
    foo.Close();
}
于 2012-07-23T17:39:04.400 に答える
0

キープアライブの実装が正しく機能していないと思います。ストリームを閉じるときは、基になるソケットを閉じます。ストリームの作成をコンストラクターに移動します。

public Foo() 
{
    m_tcpClient = new TcpClient( m_ip, m_port );
    m_tcpStream = m_tcpClient.GetStream();
}

次に、オブジェクト全体が閉じられるまで、両方を存続させます。

    void IDisposable.Dispose() 
    {
        m_tcpStream.Close();
        m_tcpClient.Client.Dispose();
    }
于 2012-07-23T17:47:43.387 に答える
0

最初Executeに呼び出されると、usingcloses(disposes)になりm_tcpClientます。あなたはそれらを必要としませusing

using( var stream = m_tcpClient.GetStream() )
于 2012-07-23T18:02:20.527 に答える