随机“现有连接被远程主机强行关闭".TCP重置后 [英] Random "An existing connection was forcibly closed by the remote host." after a TCP reset

查看:43
本文介绍了随机“现有连接被远程主机强行关闭".TCP重置后的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个部分,一个客户端和一个服务器.我尝试将数据(大小> 5840字节)从客户端发送到服务器,然后服务器将数据发送回去.我循环多次,每次之间等待一秒钟.有时服务器应用程序崩溃,崩溃看起来是非常随机的错误:

I have two parts, a client and a server. And I try to send data (size > 5840 Bytes) from the client to the server and then the server sends the data back. I loop this a number of times waiting a second between each time. Sometime the server application crash, the crash seems very random the error:

未处理的异常:System.IO.IOException:无法从传输连接中读取数据:现有连接被远程主机强行关闭.--->

Unhandled Exception: System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. --->

System.Net.Sockets.SocketException:现有连接被远程主机强行关闭

System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host

在System.Net.Sockets.Socket.Receive(字节[]缓冲区,Int32偏移量,Int32大小,SocketFlags socketFlags)

at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)

at System.Net.Sockets.NetworkStream.Read(Byte [] buffer,Int32 offset,Int32 s大小)

at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 s ize)

-内部异常堆栈跟踪的结尾---

--- End of inner exception stack trace ---

at System.Net.Sockets.NetworkStream.Read(Byte [] buffer,Int32 offset,Int32 s大小)

at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 s ize)

在TCP_Server.Program.Main(String [] args)

at TCP_Server.Program.Main(String[] args)

客户端代码(在循环内):

Client code (This is inside the loop):

            try
            {
                Int32 port = 13777;
                using (TcpClient client = new TcpClient(ip, port))
                using (NetworkStream stream = client.GetStream())
                {
                    client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
                    var data = GenerateData(size);

                    sw.Start();
                    // Send the message to the connected TcpServer. 
                    stream.Write(data, 0, data.Length);

                    // Buffer to store the response bytes.
                    data = new Byte[size];

                    // Read the first batch of the TcpServer response bytes.
                    Int32 bytes = stream.Read(data, 0, data.Length);

                    sw.Stop();
                    Console.WriteLine(i + ": Done transporting " + size + " bytes to and from " + ip + " time: " +
                                      sw.ElapsedMilliseconds + " ms");
                    // Close everything.
                    stream.Close();
                    client.Close();
                }

            }
            catch (ArgumentNullException e)
            {
                Console.WriteLine("ArgumentNullException: {0}", e);
            }
            catch (SocketException e)
            {
                Console.WriteLine("SocketException: {0}", e);
            }

            sw.Reset();

服务器代码:

            Byte[] bytes = new Byte[size];

            // Enter the listening loop. 
            for (int i = 0; i < numberOfPackages; i++)
            {
                using (TcpClient client = server.AcceptTcpClient())
                using (NetworkStream stream = client.GetStream())
                {
                    client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
                    // Loop to receive all the data sent by the client. 
                    while ((stream.Read(bytes, 0, bytes.Length)) != 0)
                    {
                        // Send back a response.
                        stream.Write(bytes, 0, size);

                    }
                    client.GetStream().Close();
                    client.Close();
                }


                Console.WriteLine("Receive data size " + size);

            }

我使用wireshark监视发送的tcp程序包,发现在程序崩溃之前,TCP RST已从客户端发送到服务器.因此,我认为问题是RST处理不正确.客户端和主机之间没有防火墙,所以这不是问题.

I have used wireshark to monitor the tcp packages sent and found that a TCP RST is sent from the client to the server before the program crashes. So I assume the problem is that the the RST is not handles correctly. There is no firewall between the client and the host so that is not the problem.

客户端和服务器的Wireshark文件位于此处: https://www.dropbox.com/sh/ctl2chq3y2c20n7/AACgIJ8IRiclqnyOyw8sqd9La?dl=0

The wireshark files for both the Client and Server is here: https://www.dropbox.com/sh/ctl2chq3y2c20n7/AACgIJ8IRiclqnyOyw8sqd9La?dl=0

所以我要么需要摆脱TCP RST,要么需要我的服务器以某种方式处理它而不会崩溃.

So either I need to get rid of the TCP RST or I need my server to handle it in some way and not crash.

我尝试使用更长的等待时间,但这无济于事.如果数据低于5840字节,我不会崩溃,这是我所知道的.

I have tried to use longer waiting time but it does not help. If the data is below 5840 Bytes I do not get any crashes, what I know of.

有什么建议或想法吗?

多亏了答案,我才可以进行以下更改:

Thanks to the answers I got it to work with the following changes:

服务器:

// Loop to receive all the data sent by the client.
int k = 0;
while (k < size)
{
   int bytesRead = stream.Read(bytes, 0, bytes.Length);
   k += bytesRead;
}
// Send back a response.
stream.Write(bytes, 0, size);

与在客户端接收时相同.因为我首先要发送所有数据,然后让服务器响应,所以这对我的应用程序有效.

And the same when receiving on the client side. Since I first want to send all data and then let the server respond this works for my application.

推荐答案

我看到两个问题:

  1. 您假设读取 size 个字节实际上将读取 size 个字节.它不是.TCP是流协议.读操作至少读取一个字节.那是唯一的保证.
  2. 您的代码将随机死锁.客户端将数据写入服务器.服务器将其回显.但是客户端在编写所有内容之前不会阅读.如果写入的内容超出网络缓冲区可以承受的范围,则将导致死锁.客户端必须同时读写.可能您需要另一个线程/任务来读回数据.解决该问题的一个好方法是启动一个编写器任务,一个读取器任务,然后执行Task.WhenAll/WaitAll将它们重新加入.
  1. You are assuming that a read for size bytes will actually read size bytes. It does not. TCP is a streaming protocol. A read reads at least one byte. That's the only guarantee given.
  2. Your code will randomly deadlock. The client writes data to the server. The server echos it back. But the client will not read until it has written everything. If it writes more than the network buffers can take this will deadlock. The client must read and write concurrently. Probably, you need another thread/task for reading the data back. A good pattern to solve that issue would be to start one writer task, one reader task and to Task.WhenAll/WaitAll to join them back.

我不确定在什么确切情况下TCP堆栈会发送RST.可能是由于死锁导致超时.

I'm not sure under what exact circumstances a TCP stack would send a RST. Could be due to the deadlock causing a timeout.

您没有吞下任何例外,对吧?

You are not swallowing any exceptions, right?

通常,关闭连接会在后台有序关闭.但是我不确定在这一点上另一方仍在写作时会发生什么.也许答案是写操作的接收方生成了RST.当然,TCP规范会回答这个问题.如果此答案是可信任的,那么确实是Shutdown(Read)/Close(关闭/读取)/Close(关闭),随后是传入的写入操作,将RST连接.

Normally, closing a connection performs an orderly shutdown in the background. But I'm unsure about what happens when the other side is still writing at this point. Maybe the answer is that an RST is generated by the receiver of the writes. Surely, the TCP spec would answer this question. If this answer is to be trusted then indeed a Shutdown(Read)/Close followed by an incoming write would RST the connection.

修复两个问题并报告您的发现.

Fix both issues and report back with your findings.

这篇关于随机“现有连接被远程主机强行关闭".TCP重置后的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆