python - ThreadedTCPServer 工作,除非客户端是一个单独的进程
问题描述
我从这里的 Python 文档改编了下面的代码。
# filename: example.py
from datetime import datetime
import socket
import socketserver
import sys
import threading
import time
class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
data = str(self.request.recv(1024), 'ascii')
cur_thread = threading.current_thread()
response = bytes("{}: {}".format(cur_thread.name, data), 'ascii')
self.request.sendall(response)
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
allow_reuse_address = True
def client(ip, port, message):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.connect((ip, port))
sock.sendall(bytes(message, 'ascii'))
response = str(sock.recv(1024), 'ascii')
print("Received: {}".format(response))
if __name__ == "__main__":
HOST, PORT = "127.0.0.1", 9999
if sys.argv[1] == "server":
server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
with server:
ip, port = server.server_address
print(f'{ip} {port}')
server_thread = threading.Thread(target=server.serve_forever)
server_thread.start()
# these work
client(ip, port, "Hello World 1 at " + str(datetime.now()))
time.sleep(1)
client(ip, port, "Hello World 2 at " + str(datetime.now()))
time.sleep(2)
client(ip, port, "Hello World 3 at " + str(datetime.now()))
if sys.argv[1] == "client":
# these do not work, why?
client(HOST, PORT, "Hello World 1 at " + str(datetime.now()))
time.sleep(1)
client(HOST, PORT, "Hello World 2 at " + str(datetime.now()))
time.sleep(2)
client(HOST, PORT, "Hello World 3 at " + str(datetime.now()))
将此代码作为服务器运行按预期工作:
$ python3 example.py server
127.0.0.1 9999
Received: Thread-2: Hello World 1 at 2021-09-14 20:02:25.135218
Received: Thread-3: Hello World 2 at 2021-09-14 20:02:26.140889
Received: Thread-4: Hello World 3 at 2021-09-14 20:02:28.143664
我让这个终端选项卡保持运行(程序正在等待其他客户端连接),打开一个新选项卡并运行以下命令,但它会产生错误:
$ python3 example.py client
Traceback (most recent call last):
File "/Users/ashroyer-admin/repo/phd-courses/2021-F-cloudcomp/thred.py", line 45, in <module>
client(HOST, PORT, "Hello World 1 at " + str(datetime.now()))
File "/Users/ashroyer-admin/repo/phd-courses/2021-F-cloudcomp/thred.py", line 20, in client
sock.connect((ip, port))
ConnectionRefusedError: [Errno 61] Connection refused
解决方案
ConnectionRefused
通常意味着在指定的 IP/端口上没有服务器正在侦听(或者它的 backlog 已满,这在本示例中不太可能发生)。很有可能,当您尝试连接其他终端客户端时,该server
对象根本不再运行。仅仅因为您将服务器的终端保持打开状态并不意味着服务器本身仍在该终端中运行。
服务器可能会在其主线程对 3 次调用后终止client()
。您正在serve_forever()
另一个线程中运行,而不是在创建server
和调用的主线程中client()
。之后没有任何东西 - 没有循环,没有事件等 - 代码正在等待保持脚本运行,以便server_thread
可以继续为新客户提供服务。
当with server:
块结束时,server
对象被关闭。当主线程完成时,脚本退出。
我的建议是:
完全摆脱
server_thread
和 3 个电话client()
。只需调用server.serve_forever()
afterprint(f'{ip} {port}')
,然后使用其他终端来测试您的client()
代码。或者,至少删除
with server:
块。显然,“服务器线程不是守护进程,因此当主线程退出时它会继续运行。删除with server:
它就可以正常工作。 ”(感谢
@MarkTolonen)
推荐阅读
- python - pypy3 - 读取 csv 文件时出现 UnicodeDecodeError
- mysql - “您有广告爬虫错误”,但网站在任何设备/代理上都能完美运行
- c# - 使用“模板”向数组添加值
- android - 如何在 Windows 上的 android studio 3.0 中调试 NDK 代码
- vue.js - 选择选项条目仅在第一次选择尝试时显示
- xamarin.forms - 在构建 Xmarin.Forms sln 时排除 Android 构建
- javascript - 所有请求一一返回,不并发
- animation - 如何使用 convert -crop 为动画 gif/放大图像添加更多背景?
- json - 无法从链接解析 JSON - 没有错误,但函数在尝试访问 URL 后返回
- c++ - 在 C++ 中使用 OpenSSL 使用 AES128 加密字符串时出错