为什么在这个while循环中抛出NullReferenceException ?

本文关键字:NullReferenceException 循环 while 为什么 | 更新日期: 2023-09-27 18:09:44

在我的套接字应用程序中,我希望大约80-100个客户端同时连接到我的服务器。

这里是套接字。

try
{
    _serverSocket.Bind(localEndPoint);
    _serverSocket.Listen(100);
    while (maintainActiveSocket)
    {
        _serverSocket.BeginAccept(new AsyncCallback(Accept), _serverSocket);
        clientAccepted.WaitOne();
    }
}

因此,一旦我的一个客户端试图连接到服务器,这被调用,它检查这个客户端是否已经知道,如果没有将他添加到ConcurrentDictionary中,在它启动套接字之后。BeginReceive在一个while循环中不断尝试接收,只要这个套接字连接。这个while-loop在第二次接收数据时抛出NullReferenceException。 acceptedClient.sCom.Buffer应该是byte[2048],但是第二次接收数据时它是空的。为什么会这样,我该如何解决?

Socket socket = _serverSocket.EndAccept(ar);
clientAccepted.Set();
_Client acceptedClient = new _Client();
if (!Dict.connectedClients.Any((a) => a.Value.Socket == socket))
{
    acceptedClient.Socket = socket;
    Dict.connectedClients.TryAdd(getFirstKey(), acceptedClient);
}
acceptedClient = Dict.connectedClients.Single((a) => a.Value.Socket == socket).Value;
while (socket.Connected)
{
    socket.BeginReceive(
        acceptedClient.sCom.Buffer, 0, acceptedClient.sCom.Buffer.Length, 0, 
        new AsyncCallback(Receive), acceptedClient);
    receiveDone.WaitOne();
}

一旦套接字开始接收,最终调用:

private static void Receive(IAsyncResult ar)
{
    _Client client = (_Client)ar.AsyncState;
    Logger.Instance.Log("Receiving on " + client.Socket.Handle);
    int bytesRead = client.Socket.EndReceive(ar);
    Logger.Instance.Log("received " + bytesRead.ToString());
    for (int i = 0; i < bytesRead; i++)
    {
        client.sCom.TransmissionBuffer.Add(client.sCom.Buffer[i]);
        client.sCom = client.sCom.DeSerialize();
        Logger.Instance.Log("name: " + client.Clientname);
        receiveDone.Set();
    }
}

接收到的数据先前在sCom中被缓冲。缓冲区是一个字节[2048]。然后将其复制到com。TransmissionBuffer,它是一个List,然后被反序列化。

我不明白为什么第二个代码块中的缓冲区在循环的第一次迭代工作后是空的。

为什么在这个while循环中抛出NullReferenceException ?

你的问题没有包括任何关于_Client类的信息,我认为这不是一个标准的库类。所以这只是在黑暗中摸索:

我不确定client.sCom = client.sCom.DeSerialize();行做什么,但它似乎用一个新对象替换了sCom对象。旧的sCom对象显然有一个缓冲区!=null,否则前一行会导致崩溃。假定新的sCom对象没有初始化的缓冲区。


这不是直接相关的,但我必须评论你使用ConcurrentDictionary:

if (!Dict.connectedClients.Any((a) => a.Value.Socket == socket))
{
    acceptedClient.Socket = socket;
    Dict.connectedClients.TryAdd(getFirstKey(), acceptedClient);
}
acceptedClient = Dict.connectedClients.Single((a) => a.Value.Socket == socket).Value;

Dict.connectedClients.Any(...)将枚举字典的整个内容,直到找到匹配的值。它不是线程安全的,它不会使用使字典有用的快速查找,所以本质上你只是使用一个列表。

Dict.connectedClients.Single(...);有同样的问题