Python socket client 报错 Connection reset by peer 是什么原因?

ponponon
  • 1.6k
浙江

最近在学习 socket 网络编程,但是 socket client 在请求 socket server 的时候,有概率出现 ConnectionResetError: [Errno 54] Connection reset by peer

server 端的代码:👇

import socket
import sys
import time
import threading
from loguru import logger
from concurrent.futures import ThreadPoolExecutor
from concurrent.futures._base import Future

default_encoding: str = 'utf-8'

pool = ThreadPoolExecutor(
    max_workers=20,
    thread_name_prefix='simple-work-thread-pool'
)


def init_serversocket() -> socket.socket:
    serversocket = socket.socket(
        family=socket.AF_INET,
        type=socket.SOCK_STREAM
    )

    # 获取本地主机名
    host = socket.gethostname()

    logger.debug(f'host {host}')

    port = 9999

    # 绑定端口号
    serversocket.bind(('0.0.0.0', port))

    # 设置最大连接数,超过后排队
    serversocket.listen(5)

    return serversocket


def send_response(clientsocket: socket.socket, addr: tuple, response_body: bytes) -> int:
    send_len: int = clientsocket.send(response_body)
    clientsocket.close()
    return send_len


def start_request(clientsocket: socket.socket, addr: tuple) -> int:
    try:
        logger.debug(f'get message from {addr}')
        request_body: bytes = clientsocket.recv(2048)
        request_text: str = request_body.decode(encoding=default_encoding)

        response_text: str = f'server get message: {request_text}'

        response_body: bytes = response_text.encode(default_encoding)
        time.sleep(1)
        return send_response(clientsocket=clientsocket, addr=addr, response_body=response_body)
    except Exception as error:
        logger.exception(error)


def start_request_callback(future: Future) -> None:
    send_len: int = future.result()
    logger.debug(
        f'{threading.current_thread().name}, send payload len is {send_len}')


serversocket = init_serversocket()


while True:
    clientsocket, addr = serversocket.accept()

    clientsocket: socket.socket
    addr: tuple

    future: Future = pool.submit(start_request, clientsocket, addr)
    future.add_done_callback(start_request_callback)
服务端使用线程池模型:主线程监听 serversocket,并把 serversocket.accept() 之后的 clientsocket 提交到线程池中处理

client 端的代码 👇

from base64 import encode
import socket  # 客户端 发送一个数据,再接收一个数据
import json
from loguru import logger
from concurrent.futures import ThreadPoolExecutor


def send_request(index:int):
    try:
        # 声明socket类型,同时生成链接对象
        clientsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        clientsocket.connect(('127.0.0.1', 9999))  # 建立一个链接,连接到本地的6969端口

        payload = b'ponponon'

        clientsocket.send(payload)

        data = clientsocket.recv(1024)

        payload = data.decode()

        logger.debug(f'>>> {index} {payload}')

        clientsocket.close()
    except Exception as error:
        logger.exception(error)


pool = ThreadPoolExecutor(max_workers=100)
for i in range(100):
    pool.submit(send_request,i)

# pool.shutdown(wait=True)
client 也是使用线程池并发请求 server

但是很奇怪,会随机报错,请求 100 次,会错 1-60 次,反正没有一次全通过过。但也没有 100 个请求都报错

平均请求 100 次,会报错 20次的样子!

为什么?🥲

报错的具体内容如下:👇

2022-07-08 13:00:54.957 | ERROR    | __main__:send_request:26 - [Errno 54] Connection reset by peer
Traceback (most recent call last):

  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/threading.py", line 973, in _bootstrap
    self._bootstrap_inner()
    │    └ <function Thread._bootstrap_inner at 0x102c7b910>
    └ <Thread(ThreadPoolExecutor-0_3, started 6198751232)>
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/threading.py", line 1016, in _bootstrap_inner
    self.run()
    │    └ <function Thread.run at 0x102c7b640>
    └ <Thread(ThreadPoolExecutor-0_3, started 6198751232)>
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/threading.py", line 953, in run
    self._target(*self._args, **self._kwargs)
    │    │        │    │        │    └ {}
    │    │        │    │        └ <Thread(ThreadPoolExecutor-0_3, started 6198751232)>
    │    │        │    └ (<weakref at 0x10393ee30; to 'ThreadPoolExecutor' at 0x102ae7d00>, <_queue.SimpleQueue object at 0x102b186d0>, None, ())
    │    │        └ <Thread(ThreadPoolExecutor-0_3, started 6198751232)>
    │    └ <function _worker at 0x10394cca0>
    └ <Thread(ThreadPoolExecutor-0_3, started 6198751232)>
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/concurrent/futures/thread.py", line 83, in _worker
    work_item.run()
    │         └ <function _WorkItem.run at 0x10394cdc0>
    └ <concurrent.futures.thread._WorkItem object at 0x103950880>
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
             │    │   │    │       │    └ {}
             │    │   │    │       └ <concurrent.futures.thread._WorkItem object at 0x103950880>
             │    │   │    └ (3,)
             │    │   └ <concurrent.futures.thread._WorkItem object at 0x103950880>
             │    └ <function send_request at 0x102b03910>
             └ <concurrent.futures.thread._WorkItem object at 0x103950880>

> File "/Users/ponponon/Desktop/code/me/http_wsgi_asgi_tutorial/003_socket_tcp_client_select.py", line 18, in send_request
    data = clientsocket.recv(1024)
           │            └ <method 'recv' of '_socket.socket' objects>
           └ <socket.socket fd=6, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 59353)>

ConnectionResetError: [Errno 54] Connection reset by peer

我本以为是 server 处理不过来,所以导致 client 报错 [Errno 54] Connection reset by peer

但是通过查阅资料发现,tcp 的三次握手这些都是 os 来负责的。serversocket.accept() 也只是从 全连接队列 里面取连接而已。

所以我想不通是什么原因会导致这个错误发生?

回复
阅读 1.4k
3 个回答
✓ 已被采纳

好像和 listen 的大小有关系

# 设置最大连接数,超过后排队
serversocket.listen(100)

设置为 100 后就没有出现过

是不是server端放在公网服务器上,client端在本地。如果是的话,建议两个端都放在本地测看看。

右耳听风
  • 3
新手上路,请多包涵

你的例子在我的mac上跑是ok的,会不会是服务端的并发连接数超过了其承载量,例子中是100应该不至于,直接把池改小试试吧,没准呢。

宣传栏