C# TCP客户端瓶颈
我正在尝试创建一个自包含类,它维护到服务器的Tcp连接 我正在使用以下类变量:C# TCP客户端瓶颈,c#,C#,我正在尝试创建一个自包含类,它维护到服务器的Tcp连接 我正在使用以下类变量: TcpClient tcpClient; NetworkStream networkStream; BinaryReader mReader; BinaryWriter mWriter; 并使用以下代码初始化它们: tcpClient = new TcpClient(host, 443); networkStream = tcpClient.GetStream(); mReader = new BinaryRead
TcpClient tcpClient;
NetworkStream networkStream;
BinaryReader mReader;
BinaryWriter mWriter;
并使用以下代码初始化它们:
tcpClient = new TcpClient(host, 443);
networkStream = tcpClient.GetStream();
mReader = new BinaryReader(networkStream);
mWriter = new BinaryWriter(networkStream);
receiveMessage = new Thread(new ThreadStart(ReceiveMessages));
receiveMessage.Start();
我正在使用阻塞调用进行读取。来自服务器的每个数据包都以4个字节(一个int)作为前缀,这些字节定义了确切的数据包大小。我正在使用我编写的一个名为ByteBuffer的类,它有一个列表(字节)来存储输入的字节。根据服务器协议,该类具有使用ReadInt()、ReadString()等从字节列表顶部提取int和其他类型的函数
以下是接收器线程:
private void ReceiveMessages()
{
while (tcpClient.Connected)
{
if (tcpClient.Available >= 4)
{
try
{
ByteBuffer message = new ByteBuffer();
message.AddBytes(mReader.ReadBytes(4));
int mSize = message.ReadInt();
message.AddBytes(mReader.ReadBytes(mSize - 4));
MessageProcessor.Process(message);
}
catch (Exception ex)
{
Print(ex.Message);
}
}
Thread.Sleep(1);
}
Print("Receiver thread terminated.");
Reconnect();
}
作为参考,MessageProcessor是一个静态类,它查看数据包信息并适当地响应服务器
我的问题是,当连接上的流量开始变得非常高时,响应开始显著延迟。我想知道,就tcp连接而言,我是否做了一些不正确的事情?我是否应该尝试编写类的异步版本?C#List对象是否太慢而不能如此频繁地使用(在ByteBuffer中)
这是我第一次尝试网络编程,所以任何建议都会非常有用
谢谢。改用异步处理。使用线程和
线程。睡眠是邪恶的
看看你的情况
您也可以使用我的新库:我会像这样重写您的ReceiveMessages方法
删除线程。睡眠不好。使用更快的字节数组
正如@jgauffin所说,异步网络代码更好,但更容易出错。如果你刚刚开始网络编程,最好保持简单
我希望这对你更有效
注意:消息没有4字节的标题
等待你不能直接从二进制读取器mReader读取一个整数吗?你为什么需要ByteBuffer留言?BinaryReader文档:我相信服务器使用big-endian,BinaryReader使用little-endian。或者其他方式。我不记得是哪个了。如果是这样的话,那么我看不出你所做的有什么真正的错误。如果您想保持单线程,我建议使用探查器来帮助您找出速度减慢的地方。如果您的MessageProcessor.Process(message)需要一些处理时间,我建议您使用多线程。仅供参考,这篇文章似乎表明列表本质上是一个固定数组:因此使用列表对于线程来说是很好的选择,这让我对使用列表感觉更好。我使用了一个分析器,但似乎找不到代码在哪里受阻。它的大部分时间都花在“if(tcpClient.Available>=4)”这一行上,我认为这只是数据包之间的时间。我知道它速度变慢的唯一原因是,当我查看它发送的响应(在使用服务器的应用程序中)时,我看到它们的延迟时间为3-4秒。我想发送功能可能会有一些问题,但发送的使用频率较低(2包/500毫秒)。感谢您的代码,我会尽快尝试一下。Sleep()就在那里,因为没有它,程序会占用很大一部分CPU。是否有其他方法可以避免此问题?在此代码网络流中。Read将阻止,直到有足够的字节可用,因此不需要Thread.SleepOh,我错过了您删除检查可用字节的步骤。这比我现在做的更有意义。ThanksI尝试删除行以检查是否有4个字节可用,并删除了睡眠,我得到以下异常:“无法从传输连接读取数据:阻塞操作被对WSACancelBlockingCall的调用中断。”知道我做错了什么吗?我需要查看完整的程序才能回答。我猜发生这种情况是因为您与线程外部的套接字交互,或者是由于外部因素(从服务器断开的链接)。更完整的代码将负责TcpSocket上的同步(锁定-这是一种简单的方法),或者如果线程中只需要TcpClient,则应将TcpSocket的初始化放在ReceiveMessages中。如果您使用相同的套接字发送消息,那么在同一线程中发生的情况最好。
private void ReceiveMessages()
{
while (tcpClient.Connected) {
try {
var networkstream = tcpClient.GetStream();
var header = new byte[4];
networkstream.Read(header, 0, 4);
int len = 0;
// calculate length from header
// Do reverse for BigEndian, for little endian remove
Array.Reverse(header);
len = BitConverter.ToInt32(header, 0);
var message = new byte[len];
networkstream.Read(message, 0, message.Length);
// Process message
}
catch (Exception ex)
{
Print(ex.Message);
// Exit loop something went wrong
break;
}
}
Print("Receiver thread terminated.");
Reconnect();
}