Приложение Windows Sockets сервера TCP - PullRequest
2 голосов
/ 02 ноября 2011

В настоящее время у меня есть приложение 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 Framework Version: v4.0.30319 Описание: процесс был прерван из-за необработанного исключения.Сведения об исключении: стек System.InvalidOperationException: в System.Collections.ArrayList + ArrayListEnumeratorSimple.MoveNext () в MyServer.OnRecotedData (System.IAsyncResult) в System.Net.LazyAsyncResult.Complete (InttionTr)..Object) при System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup (TryCode, CleanupCode, System.Object) в System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) вSystem.Threading.ExecutionContext.Run (System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) в System.Net.ContextAwareResult.Complete (IntPtr) в System.Net.Sockets.BaseOverlappedAsyncI, UC (UC) UCSystem.Threading.NativeOverlapped *) в System.Threading._IOCompletionCallback.PerformIOCompletionCallback (UInt32, UInt32, System.Threading.NativeOverlapped *)

OnRectainedData:

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();
    }

Ответы [ 2 ]

1 голос
/ 02 ноября 2011

При подключении клиента EndAccept обычно вызывается в другом потоке, а не в потоке OnRecievedData.Если EndAccept происходит в середине foreach, перечислитель больше не действителен (коллекция изменилась).

Вы должны использовать какой-то механизм синхронизации, например lock, чтобы этого не происходило.

И я даже пропустил то, что упоминает Сухас;коллекция также изменена из одной и той же темы.

1 голос
/ 02 ноября 2011

Возможность - вам не следует изменять список, когда вы выполняете этот список.В приведенном выше примере вы удаляете элемент из ClientsList внутри цикла foreach в ClientsList

...