在我的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。
答案 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(...)
;有同样的问题。