在我的一个项目中,我实现了一个小型HTTP服务器来流式传输连接的网络摄像头的视频数据 . 对于此任务,我正在使用.NET Framework 4.5中的System.Net.Sockets.TcpListener,它侦听预配置的 endpoints 并使用AcceptSocketAsync()mtehod等待发出请求 . 您可以在下面看到相关的代码部分:
this.server = new TcpListener(endpoint);
this.server.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, new LingerOption(true, 0));
this.server.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
this.server.Start();
...
this.listenTask = Task.Factory.StartNew(this.Listen);
...
private async void Listen()
{
try
{
while (this.server.Server.IsBound)
{
Socket socket = await this.server.AcceptSocketAsync();
if (socket == null)
{
break;
}
Task.Factory.StartNew(() => this.ClientThread(socket));
}
}
catch (ObjectDisposedException)
{
Log.Debug("Media HttpServer closed.");
}
}
当我启动应用程序并且第一次启动HTTP服务器时,这很好用 . 但是,当我停止HTTP服务器(在应用程序的设置中通过CheckBox完成)时,有时不会关闭不正常的侦听套接字 . 当我通过控制台(netstat -ano)检查套接字的状态时,我可以看到套接字仍然处于LISTENING状态 . 由此产生的问题是,当我再次重新启动HTTP服务器时,我得到一个System.Net.Sockets.SocketException,并显示消息“通常只允许使用每个套接字地址一次”,这并不奇怪 .
停止HTTP服务器的相关代码部分如下:
...
if (this.server != null)
{
if (this.server.Server != null)
{
if (this.server.Server.Connected)
{
this.server.Server.Shutdown(SocketShutdown.Both);
this.server.Server.Disconnect(true);
}
this.server.Server.Close();
}
this.server.Stop();
}
...
我还跟踪我的打开连接,并在完成数据传输和停止服务器后关闭它们 . 没有任何连接套接字保持打开状态,所以我认为只有监听套接字应该与此问题相关 .
我已经在停止服务器时尝试了Shutdown(),Disconnect(),Close()和Stop()方法的各种组合/顺序,以及在启动服务器时设置/取消设置几个选项,如Linger和ReuseAddress,有时似乎首先解决问题,但几天后再次出现问题 .
我还尝试使用来自iphlpapi.dll的GetTcpTable(...)和SetTcpEntry(...)停止服务器时关闭侦听套接字,如此问题所述:How to close a TCP connection by port?不幸的是,这种方法对我不起作用(它完全改变了关于侦听套接字状态的任何信息 .
由于我对我能做的其他事情有点无能为力,我在这里问是否有人知道可能导致问题的原因或解决方法 . 任何帮助将不胜感激 .
亲切的问候,克里斯
4 回答
你应该几乎总是单独留下
TcpListener.Server
. 它就在那里你可以在它上面设置套接字选项,而不是用它来控制 .所以
Listen
应该是:(假设您确实希望每个客户端有一个线程,一般我不建议使用这个架构) .
当你准备停下来时,就停下来:
在服务器套接字上,侦听套接字不需要关闭和断开连接 . 只有连接的套接字才需要这些调用 . 用以下代码替换套接字停止:
如果您没有任何特殊要求,建议仅使用
TcpListener
类及其方法,或者如果您有此类要求,请不要使用TcpListener
并从Raw套接字开始 .TcpListener
class足以提供类似的方法Start(), AcceptTcpClient()
和Stop()
.您可以创建
List<TcpClient>
并循环遍历每个客户端,并在TcpListener
实例上调用Stop()
后调用client.close()
.MSDN上有一个非常好的客户端服务器通信示例:http://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener(v=vs.110).aspx
问候
关闭它们后,我会处理你的套接字连接 . 文档说它们应该在关闭后处理,但我个人想说什么时候处理任何使用IDisposable接口的东西 .