我研究了很多小时,尝试了很多不同的方法来解决这个问题,但我被卡住了。我正在尝试创建一个异步套接字,它将从多个线程进行访问。它往往运行良好,直到我有几个线程试图同时发送。发送没有错误,唯一的问题是当EndReceive()尝试读取数据时,它返回0个字节,套接字错误为"success"。我读到这意味着这是一次优雅的关闭,服务器没有更多的数据可发送,但我连接的服务器类型不应该发送所有数据,它不是那种类型的服务器。应该总是有要读取的数据,而且不应该关闭。
我过去发送的线程有几个System.Threading.Timers,但我读到它们并不完全是线程安全的。我也尝试过使用System.Timers.Timer,但结果是一样的。我还尝试过只使用一个线程一次发送大量数据包,在这两个线程之间睡眠100毫秒,我会得到同样的结果。
接收代码如下。对于发送,我只尝试了常规阻止发送和BeginSend,但没有什么不同。
void Receive()
{
try
{
if (_datacb == null)
_datacb = new AsyncCallback(OnRecvData);
byte[] buffer = new byte[FBufferSize];
FSocket.BeginReceive(buffer, 0, FBufferSize, SocketFlags.None, _datacb, buffer);
}
catch (SocketException ex)
{
OnSocketError(ex);
}
}
void OnRecvData(IAsyncResult ar)
{
try
{
SocketError err;
int bytesRead = FSocket.EndReceive(ar, out err);
if (bytesRead == 0)
{
throw new SocketException();
}
byte[] buffer = ar.AsyncState as byte[];
FReceived.AddBytes(buffer, bytesRead);
ByteBuffer message = FReceived.GetNextMessage();
while (message != null)
{
Process(message);
message = FReceived.GetNextMessage();
}
}
catch (SocketException ex)
{
OnSocketError(ex);
}
Receive();
}
我以为可能是服务器因为发送速度太快而关闭了套接字,但实际上我有一个在VS2008中制作的阻塞版本,我可以使用50个不同的定时器,每秒发送1个数据包,而且我没有断开连接。我在VS2010中尝试了几乎相同的代码,bytesRead为0。我还在VS2008中尝试了asycsocket代码,只是想看看是否发生了什么奇怪的事情,但在VS2008中,它仍然给了我bytesRead==0。对于不会断开我连接的阻塞代码:
tcpClient = new TcpClient(host, 443);
networkStream = tcpClient.GetStream();
mReader = new BinaryReader(networkStream);
mWriter = new BinaryWriter(networkStream);
receiveMessage = new Thread(new ThreadStart(ReceiveMessages));
receiveMessage.Start();
private void ReceiveMessages()
{
while (true)
{
if ((tcpClient != null) && (tcpClient.Connected))
{
if (tcpClient.Available >= 4)
{
if (!isConnected) isConnected = true;
try
{
ByteBuffer message = new ByteBuffer();
message.AddBytes(mReader.ReadBytes(4));
int mSize = message.ReadInt();
message.AddBytes(mReader.ReadBytes(mSize - 4));
processor.Process(message);
}
catch (Exception ex)
{
Print("Recv Msg: " + ex.Message);
}
}
Thread.Sleep(1);
}
}
发送:
mWriter.Write(send);
mWriter.Flush();
对它不太满意,因为它使用了大量的CPU。我尝试了其他方法来在不使用那么多CPU的情况下实现这样的阻塞套接字,但它们也往往会断开连接。
套接字不是线程安全的。参见此处
您应该同步对套接字的访问,或者让一个线程处理所有这些(我认为这更干净,也会使调试更容易)。
显然,它与实际发送无关,而是与正在发送的数据有关。服务器期望每个数据包都发送一个特定的指纹,这是一种加密类型。每次获取指纹时,都必须调整一个值。我对实际发送进行了线程锁定,但它需要在计算指纹的部分进行锁定。有些数据包发送时带有错误的指纹,因为它们的计算顺序不正确,所以服务器以这种方式断开了连接。
我可能应该在我的问题中提到这一点,但我认为这无关紧要。
Socket可以读取0个字节。这很正常。您要做的是再次读取,直到获得完整的数据包。当人们期望套接字读取的字节数与服务器发送的字节数相同时,这是一个常见的错误。但事实上,数据可能会变得支离破碎,你只会得到数据块。因此,您的代码应该准备好从套接字组装数据块,因为数据碎片迫在眉睫。