C#TCP客户端丢失数据包

C#TCP客户端丢失数据包,c#,asynchronous,tcpclient,beginread,C#,Asynchronous,Tcpclient,Beginread,当我对我的网络代码进行压力测试时,我遇到了一些问题。基本上,一旦设置了套接字,它就会调用: NetworkStream networkStream = mClient.GetStream(); networkStream.BeginRead(buffer, 0, buffer.Length, ReadCallback, buffer); private void ReadCallback(IAsyncResult result) { try

当我对我的网络代码进行压力测试时,我遇到了一些问题。基本上,一旦设置了套接字,它就会调用:

NetworkStream networkStream = mClient.GetStream();
networkStream.BeginRead(buffer, 0, buffer.Length, ReadCallback, buffer);


private void ReadCallback(IAsyncResult result)
        {
            try
            {
                int read;
                NetworkStream networkStream;
                try
                {
                    networkStream = mClient.GetStream();
                    read = networkStream.EndRead(result);
                }
                catch
                {
                    return;
                }

                if (read == 0)
                {
                    //The connection has been closed.
                    return;
                }

                var readBuffer = (byte[])result.AsyncState;
                var readCount = readBuffer.Length;
                while (readCount < 4)
                {
                    readCount += networkStream.Read(readBuffer, 0, readBuffer.Length - readCount);
                }
                var length = BitConverter.ToInt32(readBuffer, 0);
                var messageBuffer = new byte[length];
                readCount = 0;
                while (readCount < length)
                {
                    readCount += networkStream.Read(messageBuffer, 0, messageBuffer.Length - readCount);
                }
                else
                {
                    RaiseMessageReceived(this, messageBuffer);
                }
                //Then start reading from the network again.
                readBuffer = new byte[4]; //may not need to reset, not sure
                networkStream.BeginRead(readBuffer, 0, readBuffer.Length, ReadCallback, readBuffer);
            }
            catch(Exception)
            {
                //Connection is dead, stop trying to read and wait for a heal to retrigger the read queue
                return;
            }
        }
NetworkStream NetworkStream=mClient.GetStream();
networkStream.BeginRead(buffer,0,buffer.Length,ReadCallback,buffer);
私有void ReadCallback(IAsyncResult结果)
{
尝试
{
int-read;
网络流;
尝试
{
networkStream=mClient.GetStream();
read=networkStream.EndRead(结果);
}
抓住
{
返回;
}
如果(读==0)
{
//连接已关闭。
返回;
}
var readBuffer=(字节[])result.AsyncState;
var readCount=readBuffer.Length;
而(读取计数<4)
{
readCount+=networkStream.Read(readBuffer,0,readBuffer.Length-readCount);
}
var length=BitConverter.ToInt32(readBuffer,0);
var messageBuffer=新字节[长度];
读取计数=0;
while(读取计数<长度)
{
readCount+=networkStream.Read(messageBuffer,0,messageBuffer.Length-readCount);
}
其他的
{
RaiseMessageReceived(此,messageBuffer);
}
//然后再从网络上开始阅读。
readBuffer=新字节[4];//可能不需要重置,不确定
networkStream.BeginRead(readBuffer,0,readBuffer.Length,ReadCallback,readBuffer);
}
捕获(例外)
{
//连接已断开,请停止尝试读取,并等待heal重新触发读取队列
返回;
}
}
下面是我的发送方法

private byte[] GetMessageWithLength(byte[] bytes)
        {
            //Combine the msg length to the msg
            byte[] length = BitConverter.GetBytes(bytes.Length);
            var msg = new byte[length.Length + bytes.Length];
            Buffer.BlockCopy(length, 0, msg, 0, length.Length);
            Buffer.BlockCopy(bytes, 0, msg, length.Length, bytes.Length);
            return msg;
        }

public override bool Send(byte[] bytes)
        {
            lock (sendQueue)
            {
                sendQueue.Enqueue(bytes);
                Interlocked.Increment(ref sendQueueSize);
            }
            if (!mClient.Connected)
            {
                if (Connect())
                {
                    RaiseConnectionChanged(this, true, Localisation.TCPConnectionEstablished);
                }
                else
                {
                    RaiseConnectionChanged(this, false, (bytes.Length > 0 ? Localisation.TCPMessageFailed : Localisation.TCPMessageConnectionLost));
                }
            }

            try
            {
                NetworkStream networkStream = mClient.GetStream();

                lock (sendQueue)
                {
                    if (sendQueue.Count == 0)
                    {
                        return true;
                    }
                    bytes = sendQueue.Dequeue();
                }
                var msg = GetMessageWithLength(bytes);
                //Start async write operation
                networkStream.BeginWrite(msg, 0, msg.Length, WriteCallback, null);
            }
            catch (Exception ex)
            {
                RaiseConnectionChanged(this, false, (bytes.Length > 0 ? Localisation.TCPMessageFailed : Localisation.TCPMessageConnectionLost));
            }
            return true;
        }

        /// <summary>
        /// Callback for Write operation
        /// </summary>
        /// <param name="result">The AsyncResult object</param>
        private void WriteCallback(IAsyncResult result)
        {
            try
            {
                NetworkStream networkStream = mClient.GetStream();
                while (sendQueue.Count > 0)
                {
                    byte[] bytes;
                    lock (sendQueue)
                    {
                        if (sendQueue.Count == 0)
                        {
                            break;
                        }
                        bytes = sendQueue.Dequeue();
                    }
                    var msg = GetMessageWithLength(bytes);
                    networkStream.Write(msg, 0, msg.Length);
                    Interlocked.Decrement(ref sendQueueSize);
                }
                networkStream.EndWrite(result);
                mLastPacketSentAt = Environment.TickCount;
                Interlocked.Decrement(ref sendQueueSize);
            }
            catch (Exception ex)
            {
                RaiseConnectionChanged(this, false, Localisation.TCPMessageConnectionLost);
            }
        }
private byte[]GetMessageWithLength(byte[]bytes)
{
//将味精长度与味精长度合并
byte[]length=位转换器.GetBytes(bytes.length);
var msg=新字节[length.length+bytes.length];
BlockCopy(长度,0,消息,0,长度,长度);
Buffer.BlockCopy(字节,0,msg,length.length,bytes.length);
返回味精;
}
公共覆盖布尔发送(字节[]字节)
{
锁(发送队列)
{
sendQueue.Enqueue(字节);
联锁。增量(参考sendQueueSize);
}
如果(!mClient.Connected)
{
if(Connect())
{
RaiseConnectionChanged(这是真的,本地化。TCPCONNECTION已建立);
}
其他的
{
RaiseConnectionChanged(此,false,(bytes.Length>0?Localization.TCPMessageFailed:Localization.TCPMessageConnectionLost));
}
}
尝试
{
NetworkStream NetworkStream=mClient.GetStream();
锁(发送队列)
{
如果(sendQueue.Count==0)
{
返回true;
}
bytes=sendQueue.Dequeue();
}
var msg=GetMessageWithLength(字节);
//启动异步写入操作
networkStream.BeginWrite(msg,0,msg.Length,WriteCallback,null);
}
捕获(例外情况除外)
{
RaiseConnectionChanged(此,false,(bytes.Length>0?Localization.TCPMessageFailed:Localization.TCPMessageConnectionLost));
}
返回true;
}
/// 
///写操作的回调
/// 
///AsyncResult对象
私有无效写回(IAsyncResult结果)
{
尝试
{
NetworkStream NetworkStream=mClient.GetStream();
而(sendQueue.Count>0)
{
字节[]字节;
锁(发送队列)
{
如果(sendQueue.Count==0)
{
打破
}
bytes=sendQueue.Dequeue();
}
var msg=GetMessageWithLength(字节);
networkStream.Write(消息,0,消息长度);
联锁减量(参考尺寸);
}
networkStream.EndWrite(结果);
mLastPacketSentAt=Environment.TickCount;
联锁减量(参考尺寸);
}
捕获(例外情况除外)
{
RaiseConnectionChanged(this,false,localization.TCPMessageConnectionLost);
}
}
但是,是的,当我对系统进行压力测试时(比如说500个左右的客户端同时发送大量消息),我注意到可能每400万个客户端中就有一个数据包没有被接收到。我不确定问题是在发送还是在接收,这就是为什么我将这两种方法都包括在内。然而,我要指出,如果我选择从客户机发送另一个数据包,它仍然正确地发送和接收数据包,因此它不仅仅是排队或其他什么

有人能看到我缺少的东西吗?

两个读取循环(例如
而(readCount
)有问题。你总是在偏移量为零的位置阅读。你应该以不断增加的偏移量阅读

这将导致覆盖已读取的数据

另外,我不确定混合使用同步和异步读取是否是一个好主意。这样一来,您就失去了异步代码的好处,仍然需要处理回调和suc