Reputation: 1275
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();
}
Upvotes: 2
Views: 1787
Reputation: 8468
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 the foreach
loop on ClientsList
Upvotes: 1
Reputation: 26446
When a client connects, EndAccept
will usually be invoked on another thread than the thread OnRecievedData
is running on. If EndAccept
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.
Upvotes: 1