C# 读取TCP数据流时应该怎么 读取才能不会丢失数据,有什么思路吗?怎么使用缓冲区?

2024年12月01日 01:24
有1个网友回答
网友(1):

分线程处理是可以的. 粘包和分包的问题需要你定义封包协议, 设定特定的字段进行判断.
给一个例子参考一下吧:
int totalRecvCount = 0;
int count = 5;
string message = String.Empty;
while (count > 0) // 循环接收数据, 到达到异常计数或接收完成, 则退出循环
{
try
{
// 接收数据
int recvCount = client.Client.Receive(bufRecv);
if (recvCount < 7)
{
count--;
}
else
{
message = "received data size: " + recvCount.ToString();
getMessageHandler(message);
totalRecvCount += recvCount;
// 不分分包和粘包, 一律将数据转存到缓冲区中
byte[] dataTemp = new byte[recvCount];
Array.Copy(bufRecv, dataTemp, recvCount);
buf.AddRange(dataTemp);
int curPackLength = 0;
while (buf.Count > 0)
{
curPackLength = BitConverter.ToInt32(buf.ToArray(), 2);// 包长度
if (buf.Count < curPackLength) break; //不够包长度指示的大小,则退出
if (buf[0] != 0xfe || buf[curPackLength - 1] != 0xef)
{
count = 0;//数据异常, 退出连接
break;
}
Protocol protocol = Protocol.Parse(buf.ToArray(), 0, curPackLength);
buf.RemoveRange(0, curPackLength); // 移除已经取得的包

switch (protocol.category)
{
case Category.None:
break;
case Category.Hello:
if (protocol.data.Length > 0)
{
message = Encoding.Default.GetString(protocol.data);
getMessageHandler(message);
}
break;
case Category.Bye:
if (protocol.data.Length > 0)
{
message = Encoding.Default.GetString(protocol.data);
getMessageHandler(message);
}
break;
case Category.DownloadResponseNoFile:
if (protocol.data.Length > 0)
{
message = Encoding.Default.GetString(protocol.data);
getMessageHandler(message);
}
count = 0;//直接退出连接
break;
case Category.DownloadResponseDataLength:
int length = 0;
if (protocol.data.Length == 4)
{
length = BitConverter.ToInt32(protocol.data, 0);
getDataLengthHandler(length);
}
break;
case Category.DownloadResponse:
// buf(解压前)--> memorystream --> GZipStream --> 解压到 buf(解压后) --> wirte to fileStream
ms.Position = 0;
ms.Write(protocol.data, 0, protocol.data.Length);
ms.Position = 0;
int deCompressCount = decompressedStream.Read(bufDeCompress, 0, bufDeCompress.Length);
downloadResponseHandler(bufDeCompress, 0, deCompressCount);
//DownloadResponse(bufDeCompress, 0, deCompressCount);
//writer.Write(pro.data); // 解压缩前数据
break;
case Category.DownloadFinished:
message = "Recv total: " + totalRecvCount.ToString("N0") + " bytes.";
downloadFinishedHandler(message);
break;
case Category.DownloadRequest: // 服务端处理
break;
case Category.SnapFullScreenResponse:
SnapScreenHandler(protocol.data);
break;
default:
break;
}
}
}
}
catch
{
count--;
}
}

// 协议种类
public enum Category : byte
{
None = 0,
Hello = 1,
DownloadRequest = 100,
DownloadResponse,
DownloadResponseDataLength,
DownloadResponseNoFile,
DownloadFinished,
SnapFullScreenRequest = 220, // snap screen
SnapFullScreenResponse,
Bye = 255,
}