【问题标题】:TCP Sockets Server Windows ApplicationTCP 套接字服务器 Windows 应用程序
【发布时间】:2011-12-20 11:20:59
【问题描述】:

我目前有一个使用 TCP 套接字连接用户和发送/接收数据的 Windows 应用程序。当一个新用户尝试连接而其他几个用户(从不一样数量的用户)已经连接并接收数据时,应用程序崩溃。我的应用程序需要从一个人接收数据并将其发送给多个用户。应用程序每秒接收几次数据。

我的代码在出错之前所做的最后一件事是尝试将新客户端添加到列表中。似乎在尝试连接新用户时会干扰尝试发送的数据。

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

【问题讨论】:

    标签: c# .net sockets tcp


    【解决方案1】:

    一种可能性 - 当您迭代该列表时,您不应该修改该列表。在上面的示例中,您将在 ClientsList 上的 foreach 循环中从 ClientsList 中删除项目

    【讨论】:

    • AsyncCallback recieveData = new AsyncCallback(MyServer.OnRecievedData);Listener_Socket.BeginAccept(new AsyncCallback(EndAccept), Listener_Socket); 不是在不同的线程上运行吗?
    • 我指的是OnReceiveDataforeach块中的try...catch块中的代码
    【解决方案2】:

    当客户端连接时,EndAccept 通常会在另一个线程上调用,而不是OnRecievedData 正在运行的线程。如果 EndAccept 发生在 foreach 中间,则枚举器不再有效(集合已更改)。

    您应该使用某种同步机制,例如lock 来防止这种情况发生。

    我什至错过了 Suhas 提到的内容;该集合也是在同一个线程中修改的。

    【讨论】:

    • 我的 foreach 被锁了,但程序仍然崩溃并出现同样的错误。
    • 只有在对对象的所有访问都使用相同的锁时,才能保护对象不被更改。您可以创建一个readonly object _myClientListLock = new object() 并在您访问您的列表时锁定它。
    • 如果客户端连接到服务器监听端口并且发送落后,这是因为服务器端还是客户端?
    • lock(ClientList.SyncRoot) 是否足够?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-13
    • 1970-01-01
    • 1970-01-01
    • 2016-05-01
    • 1970-01-01
    • 2015-10-06
    • 1970-01-01
    相关资源
    最近更新 更多