c# 异步连接,连接重用异常

jackyliud 2017-04-24 09:35:14
我使用c#的SocketAsyncEventArgs进行异步连接操作,遇到了如下问题。
1、socket服务监控启动后,从客户端连接能够正常连接成功,并且能够接收数据。
2、测试将客户端连接断开,重新发送客户端连接。
3、客户端连接,使用还没有使用的客户端连接池资源,连接和数据接收能够正常。
4、当前一个连接断开并且客户端连接的资源已经释放后,如果新的连接使用已经释放的连接池资源时,出现了连接异常。异常打印如下:
在 System.Net.Sockets.SocketAsyncEventArgs.StartOperationCommon(Socket socket)
在 System.Net.Sockets.Socket.ReceiveAsync(SocketAsyncEventArgs e)
在 XXXXX.AsyncSocketServer.ProcessAccept(SocketAsyncEventArgs acceptEventArgs)
位置 xxxxx\AsyncSocketCore\AsyncSocketServer.cs:行号 124

我理解的是,当之前的的客户端连接结束后,并且服务对应的连接池资源已经释放后,重新再使用,应该是可以的,但是目前出现这样的异常,请大虾们指点。



...全文
699 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
浅蓝色12138 2018-03-14
  • 打赏
  • 举报
回复
引用 13 楼 DOwnstairs 的回复:
[quote=引用 12 楼 xueluolingxin 的回复:] @jackyliud 您好,请问这个问题您是怎么解决的呢?我也遇到这个问题了
这个问题我遇到过,而且解决了。就是因为连接复用的问题。因为上一个并没有正确的关闭,而现在这个又使用了这个SAEA的socket 方法是判断确定关闭,而且要加lock之类的来保证多线程执行的正确性。lock是必须的。。。。我加了好几层。。才控制住[/quote] @SoulRed 您好,能留下qq或微信,请教一下吗?您也可以加我的qq:407512521 谢谢
SoulRed 2018-03-12
  • 打赏
  • 举报
回复
引用 12 楼 xueluolingxin 的回复:
@jackyliud 您好,请问这个问题您是怎么解决的呢?我也遇到这个问题了
这个问题我遇到过,而且解决了。就是因为连接复用的问题。因为上一个并没有正确的关闭,而现在这个又使用了这个SAEA的socket 方法是判断确定关闭,而且要加lock之类的来保证多线程执行的正确性。lock是必须的。。。。我加了好几层。。才控制住
浅蓝色12138 2018-03-10
  • 打赏
  • 举报
回复
@jackyliud 您好,请问这个问题您是怎么解决的呢?我也遇到这个问题了
jackyliud 2017-04-24
  • 打赏
  • 举报
回复
但是,在我的守护线程中,做了处理,就是在5分钟内,如果对应的连接没有数据更新,就会将这个连接的资源关闭
xdashewan 2017-04-24
  • 打赏
  • 举报
回复
这个问题是由于你对一个已经开始accept,receive或者send的SocketAsyncEventArgs对象,再一次这些操作就会引发这个异常
jackyliud 2017-04-24
  • 打赏
  • 举报
回复
在 IOCP_App.AsyncSocketServer.ProcessAccept(SocketAsyncEventArgs acceptEventArgs) 位置 F:\tool\source\DuongProject\IOCP_App\IOCP_App\AsyncSocketCore\AsyncSocketServer.cs:行号 124 2017-04-20 11:45:31,126 [5508] INFO VNMS_ServerLog [(null)] - Client connection accepted. Local Address: 10.16.4.75:22280, Remote Address: 10.16.4.213:10663 2017-04-20 11:45:31,139 [5508] ERROR VNMS_ServerLog [(null)] - Accept client System.Net.Sockets.Socket error, message: "现在已经正在使用此 SocketAsyncEventArgs 实例进行异步套接字操作。"; 2017-04-20 11:45:31,140 [5508] ERROR VNMS_ServerLog [(null)] - 在 System.Net.Sockets.SocketAsyncEventArgs.StartOperationCommon(Socket socket) 在 System.Net.Sockets.Socket.ReceiveAsync(SocketAsyncEventArgs e) 在 IOCP_App.AsyncSocketServer.ProcessAccept(SocketAsyncEventArgs acceptEventArgs) 位置 F:\tool\source\DuongProject\IOCP_App\IOCP_App\AsyncSocketCore\AsyncSocketServer.cs:行号 124 2017-04-20 11:45:31,140 [5508] INFO VNMS_ServerLog [(null)] - Client connection accepted. Local Address: 10.16.4.75:22280, Remote Address: 10.16.4.213:10665 2017-04-20 11:45:31,148 [5508] ERROR VNMS_ServerLog [(null)] - Accept client System.Net.Sockets.Socket error, message: "现在已经正在使用此 SocketAsyncEventArgs 实例进行异步套接字操作。"; 2017-04-20 11:45:31,323 [5508] ERROR VNMS_ServerLog [(null)] - 在 System.Net.Sockets.SocketAsyncEventArgs.StartOperationCommon(Socket socket) 这些就是异常信息
xdashewan 2017-04-24
  • 打赏
  • 举报
回复
具体异常信息呢
jackyliud 2017-04-24
  • 打赏
  • 举报
回复
主服务客户端连接监视线程代码: class DaemonThread : Object { private Thread m_thread; private AsyncSocketServer m_asyncSocketServer; public DaemonThread(AsyncSocketServer asyncSocketServer) { m_asyncSocketServer = asyncSocketServer; m_thread = new Thread(DaemonThreadStart); m_thread.Start(); } public void DaemonThreadStart() { while (m_thread.IsAlive) { AsyncSocketUserToken[] userTokenArray = null; m_asyncSocketServer.AsyncSocketUserTokenList.CopyList(ref userTokenArray); for (int i = 0; i < userTokenArray.Length; i++) { if (!m_thread.IsAlive) break; try { //5分钟检测client是否还在连接。 if((DateTime.Now - userTokenArray[i].ActiveDateTime).TotalMilliseconds > m_asyncSocketServer.SocketTimeOutMS) { lock (userTokenArray[i]) { m_asyncSocketServer.CloseClientSocket(userTokenArray[i]); } } } catch (Exception E) { VNMSFrm.Logger.ErrorFormat("Daemon thread check timeout socket error, message: {0}", E.Message); VNMSFrm.Logger.Error(E.StackTrace); } } for (int i = 0; i < 60 * 1000 / 10; i++) //每分钟检测一次 { if (!m_thread.IsAlive) break; Thread.Sleep(10); } } } public void Close() { m_thread.Abort(); m_thread.Join(); } }
jackyliud 2017-04-24
  • 打赏
  • 举报
回复
服务器异步主流程代码: private void BuildingSocketInvokeElement(AsyncSocketUserToken userToken) { userToken.AsyncSocketInvokeElement = new ElevatorStatusProtocol(this, userToken); if (userToken.AsyncSocketInvokeElement != null) { VNMSFrm.Logger.InfoFormat("Building socket invoke element {0}.Local Address: {1}, Remote Address: {2}", userToken.AsyncSocketInvokeElement, userToken.ConnectSocket.LocalEndPoint, userToken.ConnectSocket.RemoteEndPoint); } } private bool ProcessSend(SocketAsyncEventArgs sendEventArgs) { AsyncSocketUserToken userToken = sendEventArgs.UserToken as AsyncSocketUserToken; if (userToken.AsyncSocketInvokeElement == null) return false; userToken.ActiveDateTime = DateTime.Now; if (sendEventArgs.SocketError == SocketError.Success) return userToken.AsyncSocketInvokeElement.SendCompleted(); //调用子类回调函数 else { CloseClientSocket(userToken); return false; } } public bool SendAsyncEvent(Socket connectSocket, SocketAsyncEventArgs sendEventArgs, byte[] buffer, int offset, int count) { if (connectSocket == null) return false; sendEventArgs.SetBuffer(buffer, offset, count); bool willRaiseEvent = connectSocket.SendAsync(sendEventArgs); if (!willRaiseEvent) { return ProcessSend(sendEventArgs); } else return true; } public void CloseClientSocket(AsyncSocketUserToken userToken) { if (userToken.ConnectSocket == null) return; string socketInfo = string.Format("Local Address: {0} Remote Address: {1}", userToken.ConnectSocket.LocalEndPoint, userToken.ConnectSocket.RemoteEndPoint); VNMSFrm.Logger.InfoFormat("Client connection disconnected. {0}", socketInfo); try { userToken.ConnectSocket.Shutdown(SocketShutdown.Both); } catch (Exception E) { VNMSFrm.Logger.ErrorFormat("CloseClientSocket Disconnect client {0} error, message: {1}", socketInfo, E.Message); } userToken.ConnectSocket.Close(); userToken.ConnectSocket = null; //释放引用,并清理缓存,包括释放协议对象等资源 m_maxNumberAcceptedClients.Release(); m_asyncSocketUserTokenPool.Push(userToken); m_asyncSocketUserTokenList.Remove(userToken); } }
jackyliud 2017-04-24
  • 打赏
  • 举报
回复
服务器异步主流程代码: public class AsyncSocketServer { private Socket listenSocket; private int m_numConnections; //最大支持连接个数 private int m_receiveBufferSize; //每个连接接收缓存大小 private int m_numConnectedSockets;//链接到服务器端口的客户端数量 private Semaphore m_maxNumberAcceptedClients; //限制访问接收连接的线程数,用来控制最大并发数 private int m_socketTimeOutMS; //Socket最大超时时间,单位为MS public int SocketTimeOutMS { get { return m_socketTimeOutMS; } set { m_socketTimeOutMS = value; } } private AsyncSocketUserTokenPool m_asyncSocketUserTokenPool; private AsyncSocketUserTokenList m_asyncSocketUserTokenList; public AsyncSocketUserTokenList AsyncSocketUserTokenList { get { return m_asyncSocketUserTokenList; } } private LogOutputSocketProtocolMgr m_logOutputSocketProtocolMgr; public LogOutputSocketProtocolMgr LogOutputSocketProtocolMgr { get { return m_logOutputSocketProtocolMgr; } } private UploadSocketProtocolMgr m_uploadSocketProtocolMgr; public UploadSocketProtocolMgr UploadSocketProtocolMgr { get { return m_uploadSocketProtocolMgr; } } private DownloadSocketProtocolMgr m_downloadSocketProtocolMgr; public DownloadSocketProtocolMgr DownloadSocketProtocolMgr { get { return m_downloadSocketProtocolMgr; } } private DaemonThread m_daemonThread; public AsyncSocketServer(int numConnections) { m_numConnections = numConnections;//default 8000 m_receiveBufferSize = ProtocolConst.ReceiveBufferSize;//1024*4 m_asyncSocketUserTokenPool = new AsyncSocketUserTokenPool(numConnections); m_asyncSocketUserTokenList = new AsyncSocketUserTokenList(); m_maxNumberAcceptedClients = new Semaphore(numConnections, numConnections); m_logOutputSocketProtocolMgr = new LogOutputSocketProtocolMgr(); m_uploadSocketProtocolMgr = new UploadSocketProtocolMgr(); m_downloadSocketProtocolMgr = new DownloadSocketProtocolMgr(); } public void Init() { AsyncSocketUserToken userToken; for (int i = 0; i < m_numConnections; i++) //按照连接数建立读写对象 { userToken = new AsyncSocketUserToken(m_receiveBufferSize); userToken.ReceiveEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed); userToken.SendEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed); m_asyncSocketUserTokenPool.Push(userToken); } } public void Start(IPEndPoint localEndPoint) { listenSocket = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); listenSocket.Bind(localEndPoint); listenSocket.Listen(m_numConnections); VNMSFrm.Logger.InfoFormat("Start listen socket {0} success", localEndPoint.ToString()); //for (int i = 0; i < 64; i++) //不能循环投递多次AcceptAsync,会造成只接收8000连接后不接收连接了 StartAccept(null); m_daemonThread = new DaemonThread(this); } public void Close() { if (listenSocket != null && listenSocket.Connected) { listenSocket.Close(); } } public void StartAccept(SocketAsyncEventArgs acceptEventArgs) { if (acceptEventArgs == null) { acceptEventArgs = new SocketAsyncEventArgs(); acceptEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(AcceptEventArg_Completed); } else { acceptEventArgs.AcceptSocket = null; //释放上次绑定的Socket,等待下一个Socket连接 } m_maxNumberAcceptedClients.WaitOne(); //获取信号量 bool willRaiseEvent = listenSocket.AcceptAsync(acceptEventArgs); if (!willRaiseEvent) { ProcessAccept(acceptEventArgs); } } void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs acceptEventArgs) { try { ProcessAccept(acceptEventArgs); } catch (Exception E) { VNMSFrm.Logger.ErrorFormat("Accept client {0} error, message: {1}", acceptEventArgs.AcceptSocket, E.Message); VNMSFrm.Logger.Error(E.StackTrace); } } private void ProcessAccept(SocketAsyncEventArgs acceptEventArgs) { VNMSFrm.Logger.InfoFormat("Client connection accepted. Local Address: {0}, Remote Address: {1}", acceptEventArgs.AcceptSocket.LocalEndPoint, acceptEventArgs.AcceptSocket.RemoteEndPoint); AsyncSocketUserToken userToken = m_asyncSocketUserTokenPool.Pop(); m_asyncSocketUserTokenList.Add(userToken); //添加到正在连接列表 userToken.ConnectSocket = acceptEventArgs.AcceptSocket; userToken.ConnectDateTime = DateTime.Now; try { bool willRaiseEvent = userToken.ConnectSocket.ReceiveAsync(userToken.ReceiveEventArgs); //投递接收请求 if (!willRaiseEvent) { lock (userToken) { ProcessReceive(userToken.ReceiveEventArgs); } } } catch (Exception E) { VNMSFrm.Logger.ErrorFormat("Accept client {0} error, message: {1}", userToken.ConnectSocket, E.Message); VNMSFrm.Logger.Error(E.StackTrace); } StartAccept(acceptEventArgs); //把当前异步事件释放,等待下次连接 } void IO_Completed(object sender, SocketAsyncEventArgs asyncEventArgs) { AsyncSocketUserToken userToken = asyncEventArgs.UserToken as AsyncSocketUserToken; userToken.ActiveDateTime = DateTime.Now; try { lock (userToken) { if (asyncEventArgs.LastOperation == SocketAsyncOperation.Receive) ProcessReceive(asyncEventArgs); else if (asyncEventArgs.LastOperation == SocketAsyncOperation.Send) ProcessSend(asyncEventArgs); else throw new ArgumentException("The last operation completed on the socket was not a receive or send"); } } catch (Exception E) { VNMSFrm.Logger.ErrorFormat("IO_Completed {0} error, message: {1}", userToken.ConnectSocket, E.Message); VNMSFrm.Logger.Error(E.StackTrace); } } private void ProcessReceive(SocketAsyncEventArgs receiveEventArgs) { AsyncSocketUserToken userToken = receiveEventArgs.UserToken as AsyncSocketUserToken; if (userToken.ConnectSocket == null) return; userToken.ActiveDateTime = DateTime.Now; if (userToken.ReceiveEventArgs.BytesTransferred > 0 && userToken.ReceiveEventArgs.SocketError == SocketError.Success) { int offset = userToken.ReceiveEventArgs.Offset; int count = userToken.ReceiveEventArgs.BytesTransferred; if ((userToken.AsyncSocketInvokeElement == null) & (userToken.ConnectSocket != null)) //存在Socket对象,并且没有绑定协议对象,则进行协议对象绑定 { BuildingSocketInvokeElement(userToken); //offset = offset + 1; //count = count - 1; } if (userToken.AsyncSocketInvokeElement == null) //如果没有解析对象,提示非法连接并关闭连接 { VNMSFrm.Logger.WarnFormat("Illegal client connection. Local Address: {0}, Remote Address: {1}", userToken.ConnectSocket.LocalEndPoint, userToken.ConnectSocket.RemoteEndPoint); CloseClientSocket(userToken); } else { if (count > 0) //处理接收数据 { if (!userToken.AsyncSocketInvokeElement.ProcessReceive(userToken.ReceiveEventArgs.Buffer, offset, count)) { //如果处理数据返回失败,则断开连接 CloseClientSocket(userToken); } else //否则投递下次介绍数据请求 { bool willRaiseEvent = userToken.ConnectSocket.ReceiveAsync(userToken.ReceiveEventArgs); //投递接收请求 if (!willRaiseEvent) ProcessReceive(userToken.ReceiveEventArgs); } } else { bool willRaiseEvent = userToken.ConnectSocket.ReceiveAsync(userToken.ReceiveEventArgs); //投递接收请求 if (!willRaiseEvent) ProcessReceive(userToken.ReceiveEventArgs); } } } else { CloseClientSocket(userToken); } }
jackyliud 2017-04-24
  • 打赏
  • 举报
回复
sp1234: 那在msdn中的描述 执行异步套接字操作与此类模式包含以下步骤︰ 分配一个新 SocketAsyncEventArgs 上下文对象,或获取一个空闲从应用程序池。 在上下文设置的属性对象传递给该操作有关要执行 (完成回调方法、 数据缓冲区、 偏移量缓冲区,以及数据传输,例如最大数量)。 调用适当的套接字方法 (xxxAsync) 来启动异步操作。 如果异步套接字方法 (xxxAsync) 返回 true,在回调中,查询的上下文属性的完成状态。 如果异步套接字方法 (xxxAsync) 返回 false,以同步方式完成该操作。 可能的操作结果的查询的上下文属性。 重复使用另一个操作的上下文、 将它放回到该池,或将其丢弃。 这里的上下文重复使用,怎么理解呢?
  • 打赏
  • 举报
回复
你的代码太多,而且感觉异常复杂。比如什么“按照连接数建立读写对象”之类的想法也太诡异了,假设只有一个连接那么就应该只有1个读写对象,如果有10万个那么就可以有10万对象,当连接关闭了之后又释放了读写对象。怎么会去预先分配一对读写读写对象呢?从这个概念推而广之,我估计你有一大堆概念都这样来设计,这样的软件往往可以糊弄不懂技术的“技术管理人员”,我们深知这样的习惯出自什么样的程序员。这类思路绝不能用到实际大产品中。
  • 打赏
  • 举报
回复
重新连接,当然是获得是新的对象。原来的肯定是永远也不会再用了。

110,549

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧