Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 环路中接收网络数据的正确方法_C#_Sockets_Loops_Networking_Chunks - Fatal编程技术网

C# 环路中接收网络数据的正确方法

C# 环路中接收网络数据的正确方法,c#,sockets,loops,networking,chunks,C#,Sockets,Loops,Networking,Chunks,我正在编写一个C#客户端应用程序,它将连接到用python编写的服务器。我的问题是关于在循环中接收数据。应用程序结构是关于客户端请求服务器->服务器响应客户端的。当消息小于实际缓冲区大小(在服务器中设置)时,一切正常。例如:服务器端缓冲区:1024,客户端缓冲区大小:256,数据长度

我正在编写一个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字节)接收数据:

然后超时滴答作响,结束传输并将完整数据传递给以后的分析(从stb对象)。我认为使用超时是不合适的,但我不知道还有其他方法可以做到这一点。 然而,它是这样工作的。这里我们举一个例子,它不: 服务器端缓冲区:1024,客户端缓冲区:256,数据长度~8KB(python端在循环中发送数据)

然后超时滴答作响(很明显,数据是不完整的-得到1kb的8kb)。有时,循环甚至在1次运行后以28个接收字节结束,这都是在超时之前。Python表示数据已正确发送。以下是创建套接字和服务器流对象的方法:

TcpClient clientSocket = new TcpClient();
clientSocket.Connect("x.y.z.x", 1234);
NetworkStream serverStream = clientSocket.GetStream();
这不是TCP客户端的故障。对清除套接字进行了相同的尝试,创建方式如下:

new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)

然而,这是相似的。有没有办法让我的循环不超时地工作,接收所有数据?如果可能的话,我希望保持套接字同步。

为什么不转储使代码进入catch分支并找到答案的异常呢?:)

--编辑 对不起,我没看到报时表。你要问的问题是,是否有一种不超时的方法。是,不设置任何超时,并检查接收的字节数是否小于缓冲区大小

即:

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; 
    }
while((datacounter=serverStream.Read(recived,0256))>0)
{
Console.WriteLine(“接收:+datacounter.ToString());
追加(System.Text.Encoding.UTF8.GetString(recived,0,datacounter));
if(datacounter<256)//你可以走了
打破
}

我认为您的接收代码在功能上没有任何问题。我做了一个测试,只要你在超时前不停顿1.5秒地继续发送,接收器就会收到尽可能多的信号(例如8Mbs)

因此,看起来您的服务器发送的“速度”不够快

要回答您的问题,计时并不是了解您何时收到完整消息的典型方式。确定何时接收完整消息的一种常见、简单的方法是在发送端为完整消息的长度添加前缀(例如4字节int)。然后在接收端,首先读取4个字节,解码到长度,然后再读取更多字节

您还可以考虑在消息的末尾附加一个消息终止字符串,如Entry.NeWin。这样做的好处是,您可以调用StreamReader.ReadLine(),它将一直阻止,直到收到完整的消息。这仅在消息本身不能包含终止时有效

如果您无法更改服务器协议,是否有其他方法可以知道您已收到完整消息?(例如,检查消息末尾是否有换行符、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;
        }

好的,很抱歉我没有赶上serverStream.Timeout属性。你完全确定这不是客户的问题吗?您可以使用Wireshark进行嗅探,看看是否确实存在大于1.5秒的超时。Swireshark听起来是个好主意,我稍后会尝试。我确信这是一个客户端问题,用python编写的类似客户端根本没有问题。今天还重新安装了.NET以检查它是否已损坏-它没有损坏。关于您的编辑-如果最后一个数据包意外地有256长怎么办?:]嗨,Adam,如果最后一个数据包的长度是256,那么if“datacounter<256”将不会返回true,因此您不会退出循环。它小于、不小于或等于。:)
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; 
    }
        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!"); }