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

时间:2014-06-21 07:27:15

标签: c# sockets nullreferenceexception

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

这里是我的服务器的socket.BeginAccept部分:

try
{
    _serverSocket.Bind(localEndPoint);
    _serverSocket.Listen(100);

    while (maintainActiveSocket)
    {
        _serverSocket.BeginAccept(new AsyncCallback(Accept), _serverSocket);
        clientAccepted.WaitOne();
    }
}

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

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.Buffer中缓冲,这是一个字节[2048]。然后将其复制到sCom.TransmissionBuffer,这是一个List,然后反序列化。

我不明白为什么我的第二个代码块中的Buffer在循环的第一次迭代工作正常后为null。

1 个答案:

答案 0 :(得分:1)

您的问题未包含有关_Client类的任何信息,我认为该类不是标准库类。所以这只是在黑暗中刺伤:

我不确定行client.sCom = client.sCom.DeSerialize();的作用,但似乎用新的sCom对象替换了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(...)将枚举字典的全部内容,直到找到匹配的值。 It is not threadsafe 并且它不会使用使字典有用的快速查找,因此实际上您只是使用列表。

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