在兼容多线程和套接字消耗方面,我遇到过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();
}
}
Static void Main:
using( Foo foo = new Foo() ) {
for( int i = 0; i < 10; i++ ) {
foo.Execute();
}
}
错误
在for循环的第一次迭代成功完成后,我收到的错误是The operation is not allowed on non-connected sockets.
。
我理解错误的原因,(在读取响应后TcpClient.Client
关闭),但我不知道如何明确告诉套接字保持打开状态。
修改
进一步检查我从服务器返回的HTTP响应,其中包含Connection: Close
。我假设,因为这是原始TCP,它不会解析HTTP。这可能是问题的根源吗? (如果有,有办法忽略它)
答案 0 :(得分:2)
更改主方法中的顺序,因此每次迭代都会创建一个新对象
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();
}
答案 1 :(得分: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();
}
答案 2 :(得分:0)
调用第一个Execute
时,using
会关闭(处置)m_tcpClient
。您不需要那些using
s
using( var stream = m_tcpClient.GetStream() )