TCP 套接字服务器 Windows 应用程序
我目前有一个 Windows 应用程序,它使用 TCP 套接字连接用户并发送/接收数据。当新用户尝试连接而其他几个用户(用户数量不同)已经连接并接收数据时,应用程序会崩溃。我的应用程序需要从一个人接收数据并将其发送给许多用户。应用程序每秒接收几次数据。
我的代码在错误发生之前所做的最后一件事是尝试将新客户端添加到列表中。似乎当尝试连接新用户时,它会干扰尝试发送的数据。
private static void EndAccept(IAsyncResult ar)
{
Listener_Socket = (Socket)ar.AsyncState;
ClientsList.Add(Listener_Socket.EndAccept(ar));
Listener_Socket.BeginAccept(new AsyncCallback(EndAccept), Listener_Socket);
...
AsyncCallback receiveData = new AsyncCallback(MyServer.OnReceivedData);
}
事件查看器错误:
应用程序:xxxxxxxxxxxx.exe 框架版本:v4.0.30319 描述:由于未处理的异常,进程被终止。 异常信息:System.InvalidOperationException 堆栈:位于 System.Collections.ArrayList+ArrayListEnumeratorSimple.MoveNext() 在 MyServer.OnRecievedData(System.IAsyncResult) 在 System.Net.LazyAsyncResult.Complete(IntPtr) 处 System.Threading.ExecutionContext.runTryCode(System.Object) 位于 System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode, CleanupCode、System.Object)位于 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback、System.Object、布尔值)位于 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback、System.Object)位于 System.Net.ContextAwareResult.Complete(IntPtr) 位于 System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32, UInt32、System.Threading.NativeOverlapped*) 在 System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32, UInt32,System.Threading.NativeOverlapped *)
OnRecievedData:
private static void OnRecievedData(IAsyncResult ar)
{
SocketClient client = (SocketClient)ar.AsyncState;
byte[] aryRet = client.GetRecievedData(ar);
if (aryRet.Length < 1)
{
client.ReadOnlySocket.Close();
ClientsList.Remove(client);
return;
}
foreach (SocketClient clientSend in ClientsList)
{
if (client != clientSend)
try
{
clientSend.ReadOnlySocket.NoDelay = true;
clientSend.ReadOnlySocket.Send(aryRet);
}
catch
{
clientSend.ReadOnlySocket.Close();
ClientsList.Remove(client);
return;
}
}
client.SetupRecieveCallback();
}
I currently have a Windows Application that uses TCP Sockets to connect users and send/receive data. The application crashes when a new user tries to connect while several other users (never the same amount of users) are already connected and receiving data. My application needs to receive data from one person and send it out to many users. The application receives data couple times a second.
The last thing my code does before error error is trying to add a new client to the list. It seems like when trying to connect a new user it is interfering with the data attempting to be sent.
private static void EndAccept(IAsyncResult ar)
{
Listener_Socket = (Socket)ar.AsyncState;
ClientsList.Add(Listener_Socket.EndAccept(ar));
Listener_Socket.BeginAccept(new AsyncCallback(EndAccept), Listener_Socket);
...
AsyncCallback receiveData = new AsyncCallback(MyServer.OnReceivedData);
}
Event Viewer Error:
Application: xxxxxxxxxxxx.exe Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.InvalidOperationException Stack: at
System.Collections.ArrayList+ArrayListEnumeratorSimple.MoveNext() at
MyServer.OnRecievedData(System.IAsyncResult)
at System.Net.LazyAsyncResult.Complete(IntPtr) at
System.Threading.ExecutionContext.runTryCode(System.Object) at
System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode,
CleanupCode, System.Object) at
System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext,
System.Threading.ContextCallback, System.Object, Boolean) at
System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext,
System.Threading.ContextCallback, System.Object) at
System.Net.ContextAwareResult.Complete(IntPtr) at
System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32,
UInt32, System.Threading.NativeOverlapped*) at
System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32,
UInt32, System.Threading.NativeOverlapped*)
OnRecievedData:
private static void OnRecievedData(IAsyncResult ar)
{
SocketClient client = (SocketClient)ar.AsyncState;
byte[] aryRet = client.GetRecievedData(ar);
if (aryRet.Length < 1)
{
client.ReadOnlySocket.Close();
ClientsList.Remove(client);
return;
}
foreach (SocketClient clientSend in ClientsList)
{
if (client != clientSend)
try
{
clientSend.ReadOnlySocket.NoDelay = true;
clientSend.ReadOnlySocket.Send(aryRet);
}
catch
{
clientSend.ReadOnlySocket.Close();
ClientsList.Remove(client);
return;
}
}
client.SetupRecieveCallback();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
当客户端连接时,
EndAccept
通常会在运行OnRecievedData
的线程之外的另一个线程上调用。如果EndAccept
发生在 foreach 的中间,则枚举器不再有效(集合已更改)。您应该使用某种同步机制(例如
lock
)来防止这种情况发生。我什至错过了苏哈斯提到的;该集合也是在同一线程内修改的。
When a client connects,
EndAccept
will usually be invoked on another thread than the threadOnRecievedData
is running on. IfEndAccept
happens in the middle of the foreach, the enumerator is no longer valid (the collection has changed).You should use some kind of synchronization mechanism like
lock
to prevent this from happening.And I even missed what Suhas mentions; the collection is modified from within the same thread, too.
一种可能性 - 当您迭代该列表时,您不应该修改该列表。在上面的示例中,您要从
ClientsList
上的foreach
循环内的ClientsList
中删除项目A possibility - You should not modify a list when you are iterating that list. In your example above you are removing item from
ClientsList
inside theforeach
loop onClientsList