为啥主机中止连接?

Posted

技术标签:

【中文标题】为啥主机中止连接?【英文标题】:Why is host aborting connection?为什么主机中止连接? 【发布时间】:2010-12-01 04:01:15 【问题描述】:

我正在自学 Python 网络,我回忆起当我自学线程时,我遇到了this page,所以我复制了脚本,将它们更新为 Python 3.1.1 并运行它们。他们工作得很好。

然后我做了一些修改。我的目标是做一些简单的事情:

    客户端挑选一个整数并将其发送到服务器。 服务器接收到腌制的整数,解封,加倍,然后腌制并将其发送回客户端。 客户端接收腌制(和加倍)整数,将其取消腌制,然后输出。

这是服务器:

import pickle
import socket
import threading

class ClientThread(threading.Thread):
    def __init__(self, channel, details):
        self.channel = channel
        self.details = details
        threading.Thread.__init__ ( self )

    def run(self):
        print('Received connection:', self.details[0])
        request = self.channel.recv(1024)
        response = pickle.dumps(pickle.loads(request) * 2)
        self.channel.send(response)
        self.channel.close()
        print('Closed connection:', self.details [ 0 ])

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('', 2727))
server.listen(5)

while True:
    channel, details = server.accept()
    ClientThread(channel, details).start()

这里是客户端:

import pickle
import socket
import threading

class ConnectionThread(threading.Thread):
    def run(self):
        client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        client.connect(('localhost', 2727))

        for x in range(10):
            client.send(pickle.dumps(x))
            print('Sent:',str(x))
            print('Received:',repr(pickle.loads(client.recv(1024))))

        client.close()

for x in range(5):
    ConnectionThread().start()

服务器运行良好,当我运行客户端时,它成功连接并开始发送整数并按预期加倍接收它们。但是,很快它就异常了:

Exception in thread Thread-2:
Traceback (most recent call last):
  File "C:\Python30\lib\threading.py", line 507, in _bootstrap_inner
    self.run()
  File "C:\Users\Imagist\Desktop\server\client.py", line 13, in run
    print('Received:',repr(pickle.loads(client.recv(1024))))
socket.error: [Errno 10053] An established connection was aborted by the softwar
e in your host machine

服务器继续运行并正常接收连接;只有客户端崩溃。这是什么原因造成的?

编辑:我让客户使用以下代码:

import pickle
import socket
import threading

class ConnectionThread(threading.Thread):
    def run(self):
        for x in range(10):
            client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            client.connect(('localhost', 2727))
            client.send(pickle.dumps(x))
            print('Sent:',str(x))
            print('Received:',repr(pickle.loads(client.recv(1024))))
            client.close()

for x in range(5):
    ConnectionThread().start()

但是,我仍然不明白发生了什么。这不只是多次打开和关闭套接字吗?不应该有时间限制吗(你不应该在关闭套接字后这么快就打开它)?

【问题讨论】:

代码中有一些明显的错误,似乎假设一侧的 1 个 send 调用导致另一侧的 1 个 recv 调用,这可能不是真的,TCP 是流协议,它不是面向消息或数据包。但不确定这与错误消息有何关系。 @leeroy 我显然对此有点陌生,所以我完全愿意接受批评。您似乎在建议我不应该使用 TCP,因为它是流而不是面向数据包的;但是不能将数据包简单地表示为非常短的数据流吗?我知道它不是应该使用的,但这只是为了测试;显然,我打算推送比单个整数更多的数据。 @leeroy(续)我的目标是努力实现这样的东西:mcwalter.org/technology/java/httpd/tiny/index.html 仅在 Python 中。 您可以在 tcp 之上构建自己的“数据包”/记录。例如发送 1 个数字后跟换行符。然后接收端可以读取行。 1 行 = 你会知道你已经阅读了 1 个数字。 您的服务器只读取一个请求并发送一个响应。因此,要么从您的客户端删除循环,要么将一个循环添加到服务器处理程序中。您还需要一些适当的异常和流结束处理,以及服务器端的读取超时。 【参考方案1】:

您的客户端现在是正确的 - 您想要打开套接字发送数据、接收回复然后关闭套接字。

错误原始错误是由于服务器在发送第一个响应后关闭套接字导致客户端在尝试在同一连接上发送第二个消息时收到连接关闭消息。

但是,我还是不明白 这是怎么回事。这不只是 打开和关闭插座一堆 次?

是的。这是可以接受的,即使不是最高性能的做事方式。

不应该有时间吗 对此的限制(你不应该 这么快就可以打开一个套接字 关闭它)?

您可以随心所欲地打开客户端套接字,每次打开套接字时都会获得一个新的本地端口号,这意味着连接不会受到干扰。在上面的服务器代码中,它将为每个传入的连接启动一个新线程。

每个 IP 连接有 4 个部分(source_address、source_port、destination_address、destination_port),并且这个四元组(众所周知)必须随着连接而改变。除了 source_port 之外的所有内容都是针对客户端套接字固定的,因此操作系统会为您更改。

打开服务器套接字比较麻烦——如果你想快速打开一个新的服务器套接字,你的

server.bind(('', 2727))

然后您需要阅读 SO_REUSEADDR。

【讨论】:

以上是关于为啥主机中止连接?的主要内容,如果未能解决你的问题,请参考以下文章

C# 已建立的连接被主机中的软件中止

ConnectionAbortedError: [WinError 10053] 已建立的连接被主机中的软件中止

IOException:已建立的连接被主机中的软件中止

Caused by: java.io.IOException: 您的主机中的软件中止了一个已建立的连接。

Django:错误:[Errno 10053] 已建立的连接被主机中的软件中止

MySQL (MariaDB) [WinError 10053] 已建立的连接被主机中的软件中止