我正在编写一个C#客户端应用程序,它将连接到用python编写的服务器。我的问题是关于循环接收数据。应用程序结构都是关于客户端请求服务器 - >服务器响应客户端。当消息低于实际缓冲区大小(在服务器中设置)时,一切正常。例如:服务器端缓冲区:1024,客户端缓冲区大小:256,数据长度< 1KB。我使用以下代码运行我的应用程序:
int datacounter = 0;
byte[] recived = new byte[256];
StringBuilder stb = new StringBuilder();
serverStream.ReadTimeout = 1500;
try
{
while ((datacounter = serverStream.Read(recived, 0, 256)) > 0)
{
Console.WriteLine("RECIVED: " + datacounter.ToString());
stb.append(System.Text.Encoding.UTF8.GetString(recived, 0, datacounter));
}
}
catch { Console.WriteLine("Timeout!"); }
然后应用程序以4个循环(每个256字节)接收数据:
RECIVED: 256
RECIVED: 256
RECIVED: 256
RECIVED: 96
然后超时滴答,结束传输并将完整数据传递给以后的分析(来自stb对象)。我不认为使用超时是正确的,但我不知道有任何其他方法可以做到这一点。 但是,这种方式有效。这里我们举例说明,但不是: 服务器端缓冲区:1024,客户端缓冲区:256,数据长度~8kbytes(python端循环发送数据)。
RECIVED: 256
RECIVED: 256
RECIVED: 256
RECIVED: 256
然后超时滴答(显然数据不完整 - 得到1kb的8kb)。有时循环甚至在1次运行后以28个重复的字节结束,那就是在超时之前。 Python说数据已经正确发送。这是我创建socket和serverStream对象的方式:
TcpClient clientSocket = new TcpClient();
clientSocket.Connect("x.y.z.x", 1234);
NetworkStream serverStream = clientSocket.GetStream();
它不是TcpClient错误。尝试使用清晰的套接字,创建如下:
new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
然而,它的作用相似。有没有办法,让我的循环工作没有超时,接收所有数据?如果可能的话,我想保持套接字同步。
答案 0 :(得分:0)
为什么不转储使您的代码进入catch分支并查找的异常? :)
catch (Exception ex) { Console.WriteLine("Timeout because of... " + ex.Message); }
- 编辑 对不起,我没有看到这个问题。您提出的问题是,是否可以在没有超时的情况下执行此操作。是的,不要设置任何超时并检查接收的字节数是否小于缓冲区大小。
那是:
while ((datacounter = serverStream.Read(recived, 0, 256)) > 0)
{
Console.WriteLine("RECIVED: " + datacounter.ToString());
stb.append(System.Text.Encoding.UTF8.GetString(recived, 0, datacounter));
if(datacounter < 256) //you're good to go
break;
}
答案 1 :(得分:0)
我认为您的接收代码在功能上没有任何问题。我把测试放在一起,接收器尽可能多地发送它(例如8 MB),只要你在没有1.5秒暂停的情况下继续发送,然后再超时。
所以看起来你的服务器根本就没有“快速”发送。
要回答您的问题,时间并不是了解何时收到完整信息的典型方式。确定何时接收到完整消息的一种常见,简单的方法是在发送侧为完整消息的长度添加前缀(例如,4字节int)。然后在接收端,首先读取4个字节,解码为长度,然后读取更多的字节。
您还可以考虑将消息终止字符串(例如Environment.NewLine)附加到邮件的末尾。这样做的好处是可以调用StreamReader.ReadLine(),它将阻塞直到收到完整的消息。这仅在终止不能包含在消息本身中时才有效。
如果您无法更改服务器协议,是否有其他方式可以知道您已收到完整邮件? (例如,在消息末尾检查NewLine,XML结束标记或其他模式。)如果没有,也许您可以等待服务器断开连接,否则看起来您将被迫找到正确的时间平衡。
如果你想玩它,我会在下面加上测试代码。
服务器/发送方:
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
TcpListener server = new TcpListener(localAddr, 13579);
server.Start();
TcpClient clientSocket = server.AcceptTcpClient();
NetworkStream stream = clientSocket.GetStream();
int bytesSent = 0;
int bytesToSend = 1 << 25;
int bufferSize = 1024;
string testMessage = new string('X', bufferSize);
byte[] buffer = UTF8Encoding.UTF8.GetBytes(testMessage);
while (bytesSent < bytesToSend)
{
int byteToSendThisRound = Math.Min(bufferSize, bytesToSend - bytesSent);
stream.Write(buffer, 0, byteToSendThisRound);
bytesSent += byteToSendThisRound;
}
客户/接收方:
TcpClient client = new TcpClient("127.0.0.1", 13579);
NetworkStream serverStream = client.GetStream();
int totalBytesReceived = 0;
int datacounter = 0;
byte[] recived = new byte[256];
StringBuilder stb = new StringBuilder();
serverStream.ReadTimeout = 1500;
try
{
while ((datacounter = serverStream.Read(recived, 0, 256)) > 0)
{
totalBytesReceived += 256;
Console.WriteLine("RECIVED: {0}, {1}", datacounter, totalBytesReceived);
stb.Append(System.Text.Encoding.UTF8.GetString(recived, 0, datacounter));
}
}
catch { Console.WriteLine("Timeout!"); }