很奇怪的问题!异步通讯中连接上后一段时间不发送数据再次发送接收不到数据的问题

时间:2022-11-18 16:59:39
软件采用异步方式进行通讯,正常情况下连接,发送/接收数据都是正常的

但碰到一个很奇怪的情况,就是当服务端和客户端A在已连接的情况下,如果有十几分钟或更长时间双方没有发送接收任何数据,
然后客户端A再次发送数据给服务端的话,服务端就接收不到了???
但更奇怪的是,如果另一个客户端B连接上服务端的时候,并发送数据给服务端后,好像又激活了服务端,然后这两个客户端分别收到了服务端发送过来各自对应的响应数据

难道异步通信中长时间不发送/接收数据会阻塞吗?代码如下,请兄弟姐妹们帮我分析下到底是什么原因造成的,万分感谢!!


//服务端

private Socket _sockSvr;
private const int _buffersize = 2048;
private DataStruct m_DpObj = null;//DataStruct 是个自定义的类

public class DataStruct 
{
        public Socket ClientSocket = null;
        public string ID = string.Empty;
        public byte[] RecvData = new byte[2048];
        public int nReadBytesNums  = 0;
}

public int Start()
 {
       StartListen();

       _sockSvr.BeginAccept(new AsyncCallback(AcceptCallBack), _sockSvr);

       return 1;
}

private void StartListen()
 {
       _sockSvr = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

       IPEndPoint iep = new IPEndPoint(IPAddress.Any, Port);
       _sockSvr.Bind(iep);

      _sockSvr.Listen(10);
 }

private void AcceptCallBack(IAsyncResult ar)
{
       Socket handler = (Socket)ar.AsyncState;
       Socket _clientSock = handler.EndAccept(ar);

       m_DpObj = new DataStruct ();
       m_DpObj.ClientSocket = _clientSock;
       m_DpObj.ID = GetClientIp(_clientSock);

       _clientSock.BeginReceive(m_DpObj.RecvData, 0, _buffersize, SocketFlags.None, new AsyncCallback(ReceiveData), m_DpObj);
        _sockSvr.BeginAccept(new AsyncCallback(AcceptCallBack), _sockSvr);
}

private void ReceiveData(IAsyncResult ar)
{
       DataStruct ds= ar.AsyncState as DataStruct ;
       Socket tempsocket = ds.ClientSocket;
       ds.nReadBytesNums = ds.ClientSocket.EndReceive(ar);

       if (ds.nReadBytesNums > 0)
       {
               //流程处理,忽略
       }

      ds= new DataStruct ();
      ds.ClientSocket = tempsocket;

      tempsocket.BeginReceive(ds.RecvData, 0, _buffersize, SocketFlags.None, new AsyncCallback(ReceiveData), ds);
      Thread.Sleep(5);
}

6 个解决方案

#1


“客户端A再次发送数据给服务端的话,服务端就接收不到了”,
难道没有报错信息?
一般来说,如果数据量小,实时性要求低,不需要维持长连接,用完后就释放;
如果要维持长链路,如果数据实时性较低,
客户端就得有心跳机制来保证链路的活跃度
否则,即使server端没有超时清理,
好多网络设备也会自动清理非活跃的链路

#2


引用 1 楼 xian_wwq 的回复:
“客户端A再次发送数据给服务端的话,服务端就接收不到了”,
难道没有报错信息?
一般来说,如果数据量小,实时性要求低,不需要维持长连接,用完后就释放;
如果要维持长链路,如果数据实时性较低,
客户端就得有心跳机制来保证链路的活跃度
否则,即使server端没有超时清理,
好多网络设备也会自动清理非活跃的链路


没有异常,感觉socket还是维持连着的状态,因为终端始终也没断,只是发送消息给服务端服务端没有任何响应,但另一个客户端连接上后,好像服务端又被激活了一样,把要应答之前那个客户端的消息发出去了,给人的感觉像是BeginReceive被阻塞了一样

#3


如果有心跳维持就不会出现这个情况,就是在只连接但无任何交互的时候出现这个情况

#4


记录个日志(或者在 Debug.Print 打印日志),看看到底是 ds.nReadBytesNums = ds.ClientSocket.EndReceive(ar) 语句根本没执行,还是只是你的“流程处理,忽略”里边有问题。

把日志推送到具体的语句上,指明具体语言问题。不要自己根据“现象”拍着脑袋(而不动手),一叶障目。

#5


另外,就你的代码来说,所谓“流程处理,忽略”这里占用了 I/O 时间,是不好的。你或者把 tempsocket.BeginReceive... 语句放到他的前边(Sleep 5 是干什么的,你还要故意延迟程序执行?),或者把它异步处理而不要拖延 I/O。

#6


看你的描述,没有设置心跳包
搞心跳包就应该不会出问题 了

#1


“客户端A再次发送数据给服务端的话,服务端就接收不到了”,
难道没有报错信息?
一般来说,如果数据量小,实时性要求低,不需要维持长连接,用完后就释放;
如果要维持长链路,如果数据实时性较低,
客户端就得有心跳机制来保证链路的活跃度
否则,即使server端没有超时清理,
好多网络设备也会自动清理非活跃的链路

#2


引用 1 楼 xian_wwq 的回复:
“客户端A再次发送数据给服务端的话,服务端就接收不到了”,
难道没有报错信息?
一般来说,如果数据量小,实时性要求低,不需要维持长连接,用完后就释放;
如果要维持长链路,如果数据实时性较低,
客户端就得有心跳机制来保证链路的活跃度
否则,即使server端没有超时清理,
好多网络设备也会自动清理非活跃的链路


没有异常,感觉socket还是维持连着的状态,因为终端始终也没断,只是发送消息给服务端服务端没有任何响应,但另一个客户端连接上后,好像服务端又被激活了一样,把要应答之前那个客户端的消息发出去了,给人的感觉像是BeginReceive被阻塞了一样

#3


如果有心跳维持就不会出现这个情况,就是在只连接但无任何交互的时候出现这个情况

#4


记录个日志(或者在 Debug.Print 打印日志),看看到底是 ds.nReadBytesNums = ds.ClientSocket.EndReceive(ar) 语句根本没执行,还是只是你的“流程处理,忽略”里边有问题。

把日志推送到具体的语句上,指明具体语言问题。不要自己根据“现象”拍着脑袋(而不动手),一叶障目。

#5


另外,就你的代码来说,所谓“流程处理,忽略”这里占用了 I/O 时间,是不好的。你或者把 tempsocket.BeginReceive... 语句放到他的前边(Sleep 5 是干什么的,你还要故意延迟程序执行?),或者把它异步处理而不要拖延 I/O。

#6


看你的描述,没有设置心跳包
搞心跳包就应该不会出问题 了