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在一次迭代后调用,例如

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

我认为您对 KeepAlive 的实施不太正确。当您关闭流时,您正在关闭底层套接字。将您的流创建移动到构造函数。

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

当 firstExecute被调用时,usingcloses(disposes) m_tcpClient。你不需要using那些

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