You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python单服务器消息平台跨公网连接拒绝/超时问题求助

问题描述

我正在用Python开发单服务器架构的消息平台,目前已完成防火墙、端口转发及路由配置。该服务器-客户端架构在同一机器上可正常运行,但我希望通过公网IP实现两台设备跨互联网通信。尝试使用Keenetic路由器的WiFi公网IP(178.140.168.19)连接时,频繁出现“connection refused”或“connection timed out”错误,客户端信号似乎未到达服务器。

平台支持Linux和Windows系统(推荐用Linux,忽略代码中的cls,属于遗留代码),所有功能在Python 3.7环境下均可正常工作。

服务器代码

import threading
import socket
import time
import os as r
r.system(" ")

clients = set()
clients_lock = threading.Lock()

def announce(msg):
    with clients_lock:
        for c in clients:
            c.sendall(msg.encode("utf-8"))
            print(msg)

def handle_client(conn, addr):
    client = conn
    with clients_lock:
        clients.add(conn)
    while True:
        try:
            try:
                data = conn.recv(1024) 
                d = data.decode()
                d = d.split("\x00\x12\x12") # data splitting (text - nick)
            except BaseException as b:
                print(f"\033[1;37;41m<System> {addr[0]}:{addr[1]} {b} ")
                print(f"\033[1;37;41m<System> {addr[0]}:{addr[1]}, DONT EVER RETURN HERE AGAIN\033[0m")
                conn.close() 
                clients.remove(client)
                break
            if not data:
                pass
            if d[0]=="/closecon":
                announce(f"\033[1;37;42m<System> {addr[0]}:{addr[1]}, bye")
                conn.close() 
                clients.remove(client)
                break
                

            try:
                announce(f"\033[1;37;40m< {addr[0]}:{addr[1]} / \033[1;33;40m{d[1]}\033[1;37;40m > {d[0]} \033[0m")
            except BaseException as v:
                conn.close() 
                clients.remove(client)
                announce(f"\033[1;37;42m<System> {addr[0]}:{addr[1]}, bye ({v})")

        except KeyboardInterrupt:
            print("bye!")
            
 

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ip = "" # local ip
s.bind((ip, 10000)) # 8000 - 12000, the ports that mine machine accepts
s.listen(30)
print("Server started")

while True:
    conn, addr = s.accept()
    
    announce("\033[1;32;40maccepting new client, username unknown\033[0m")
    print("\033[1;32;40maccepting new client, username unknown\033[0m")
    thread = threading.Thread(target=handle_client, args=(conn, addr))
    thread.start()

客户端代码

import socket
import threading
import os as r;r.system("")

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.1.33', 10000))
loginName = input("Hello user, what's your name?\n > ")
r.system("cls")
def print_others_msg():
    global ypos
    while True:
        data = s.recv(1024)
        if data:
            print(f"> {data.decode()}"+" "*70)
            

thread = threading.Thread(target=print_others_msg)    ;thread.start()
while True:
    toSend = str(input("")+"\x00\x12\x12"+loginName).strip(" ")
    if len(toSend)>70:
        print("Text size limit!! >70                                         ")
    else:
        s.send(toSend.encode('utf8'))
排查解决方案
  • 验证端口转发有效性:

    1. 确认路由器端口转发规则是将公网端口10000映射到服务器局域网IP(如192.168.1.33)及10000端口,协议选择TCP。
    2. 用外部网络设备测试公网端口是否开放:
      # Linux/macOS
      nc -zv 178.140.168.19 10000
      # Windows
      telnet 178.140.168.19 10000
      
      若连接失败,说明端口转发未配置正确或被拦截。
  • 检查服务器防火墙:
    确保服务器防火墙允许10000端口的TCP入站连接:

    # Linux ufw命令
    sudo ufw allow 10000/tcp
    sudo ufw reload
    

    Windows需在 Defender防火墙中添加对应端口的入站规则。

  • 确认服务器网络配置:
    服务器代码中ip = ""绑定所有网卡是正确的,但要确保服务器局域网IP为静态分配(避免重启后IP变化导致端口转发失效),且该IP与端口转发规则中的目标IP一致。

  • 排查运营商NAT限制:
    部分家庭宽带的公网IP是运营商NAT后的“假公网”,此时外部无法直接访问。可通过手机流量网络测试连接,若仍失败,需联系运营商获取真实公网IP。

  • 修改客户端连接地址:
    客户端连接公网时,需将s.connect(('192.168.1.33', 10000))修改为s.connect(('178.140.168.19', 10000)),且不要在局域网内测试公网IP连接(部分路由器不支持NAT回环)。

内容的提问来源于stack exchange,提问作者UA3YSR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 01:25:58