我已经使用TcpListener类和几个客户端套接字在C#(.NET Compact Framework 2.0)中编写了一个非常基本的应用程序。
该程序可以正常运行一段时间(一次最多几个星期),但最终总是会失败。在我的客户端无法重新连接的基础上,此错误似乎对关联的NIC的all活动造成了不利影响。一旦发生这种情况,我将不再能够远程访问设备(使用CE Remote Display)-这是我获得调试附加反馈的唯一途径。因此,在这一点上,我还不能100%确定应用程序本身是否崩溃,或者是否正在通过套接字代码破坏操作系统中的某些内容。
我实现了一个从未处理过的未处理异常事件。我其余的异常处理当前会写出到GUI(一旦我无法再远程查看它,这将是无用的)。除了更改所有异常以将其记录到文件之外,我还在寻找任何其他信息或见解。
基本TcpListener代码:
_server = new TcpListener(IPAddress.Any, Config.ServerListenPort);
_server.Start();
_server.Server.BeginAccept(new AsyncCallback(OnClientConnected), null);
已连接客户端:
private static void OnClientConnected(IAsyncResult ar)
{
Socket connected = _server.Server.EndAccept(ar);
string ip = GetIpString(connected);
// only accept known clients
if (_acceptedClientsList.Contains(ip))
{
// if client already connected, close and reconnect
// perhaps there is a better way to do this?
if (_client != null)
{
_client.Close();
_client = null;
}
// set client reference
_client = connected;
// start accepting data
_client.BeginReceive(_tcpBuffer, 0, 256, 0, new AsyncCallback(tcpEndReceive), null);
}
}
客户收到:
private void tcpEndReceive(IAsyncResult ar)
{
// get count of read bytes
int readBytes = _client.EndReceive(ar);
if ((_client != null) && _client.Connected)
{
// readBytes == 0 when client issues disconnect
if (readBytes > 0)
{
// convert read bytes to string
string read = Encoding.ASCII.GetString(_tcpBuffer, 0, readBytes);
// data receive notification to owner
tcpDataReceived(new ReceiveDataEvent(read));
// listen for more incoming data
_client.BeginReceive(_tcpBuffer, 0, 256, SocketFlags.None, new AsyncCallback(tcpEndReceive), null);
}
else
{
// client disconnected
_client.Close();
_client = null;
// client-issued disconnect
tcpDataReceived(new ReceiveDataEvent("Client voluntarily disconnected."));
}
}
}
客户发送:
public void Send(string Message)
{
if ((_client != null) && _client.Connected)
{
// convert string to bytes and send
byte[] send = Encoding.ASCII.GetBytes(Message);
_client.Send(send, SocketFlags.None);
}
}
为了简洁起见,对此进行了简化。我的客户实际上是由另一个包含其他不相关信息的类“节点”管理的-但是每个节点都有一个_client字段,并如图所示进行连接。
客户端本身是简单的小型网关设备,配置为连接到服务器并转发信息。他们还每五分钟发送一次Keepalive消息。
我最初的想法可能是某处内存泄漏,但是我只是在实现一些内存诊断和日志记录。这是一个我可以少量使用的远程系统,尽管我具有测试控制器和网关单元(客户端),但条件并不完全相同,并且我至今还无法重现该问题。
TIA提供任何反馈。
编辑:
我一直在运行我的测试台演示,并根据一些评论建议定期检查服务器上的netstat。在CE5中,netstat不带-a标志,所以我一直在使用-n(不确定这是否会告诉我我需要什么...)。我已经多次断开和重新连接客户端,通过拔掉以太网等来强制半开,netstat表仅显示每个客户端一个连接(在适当的端口)。
您可能用完了服务器(Windows CE 5,32位OS)上的套接字。参见Is there a limit on number of tcp/ip connections between machines on linux?中的类似内容。 “ ...一旦关闭TCP套接字(默认情况下),该端口将保持处于TIMED_WAIT状态2分钟...”
我缺少有关每次有多少个客户端创建/关闭连接的信息。您可能需要处理套接字选项SO_REUSEADDR(https://docs.microsoft.com/en-us/previous-versions/windows/embedded/ms884940%28v%3dmsdn.10%29)。
您可以在服务器子网中进行循环网络跟踪(30分钟左右,刚好有机会看到之前发生的情况,取决于您在“崩溃”后停止跟踪的速度),以查看刚刚发生的情况在“崩溃”之前。
另一个难点是要定期重新启动服务器(一个晚上),因为所有Windows Mobile CE装置都不能24/7正常运行。
我们的客户使用很多Windows Embedded Handheld 6.5(基于CE5)设备。即使它们没有太多网络,但如果它们每天晚上重新启动,它们在一天中的运行也会最稳定。定期重新启动还会发现CE5服务器上的NIC驱动程序出现故障(谁知道某些公司的Platform软件表现不佳)。或尝试其他供应商的NIC。
BTW:我已经为Windows Mobile编写了自己的netstat:http://www.hjgode.de/wp/2013/09/24/mobile-development-netstat-know-your-devices-open-ports/。我没有在Windows CE5上对其进行测试,但是它应该也可以在CE5上工作。