按照廖雪峰老师的 TCP 编程 教程,创建了服务器和客户端两个 python 文件。环境为 win7,shell 用的是 git-bash。分别执行了服务器端和客户端的代码,但都没有任何输出。然后按照评论里的 “简单的客户端-服务器程序里” 的说法,将创建客户端和服务器的 python 代码封装到函数里,再通过命令行形式调用。

if __name__ == '__main__':
    sever()

先是报了一个如标题所示的错误:OSError: [WinError 10048] 通常每个套接字地址(协议/网络地址/端口)只允许使用一次。搜索了一下,是之前执行的 python 进程没有结束,服务器和客户端的通讯端口被占用。解决方案:换一个端口,或者通过 window 任务管理器找到 python.exe 进程,将其结束。

之后再次尝试执行 python 脚本,但在 git-bash 中依然没有输出内容。看评论里有人成功的,即使不封装成函数。一拍脑袋,突然想到之前在 git-bash 中执行一些指令,也遇到过这种情况,应该就是 shell 自身的问题。翻出 CMD,切换到脚本目录下,依次执行服务器脚本、客户端脚本,终于成功了。

最后尝试不封装成函数,看看是否能够成功。依然成功了。中间遇到一个错误提示:OSError: [WinError 10038] 在一个非套接字上尝试了一个操作。,对比代码,发现是我把结束连接的语句 s.send(b'exit') 错位,写到发送数据的循环里了。

tip: 关于 由于目标计算机积极拒绝,无法连接 的错误提示,教程的评论里也有解答,就是服务器脚本要先运行,然后再运行客户端的脚本。这个错误在 ssh 远程连接服务器中遇到好多次,就是服务器(脚本)没有启动。

以下是完整的服务器和客户端代码:

客户端:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 与服务器通讯的客户端

import socket

# 客户端程序
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 建立连接
s.connect(('127.0.0.1', 9998))
# 接受欢迎消息
print(s.recv(1024).decode('utf-8'))
for data in [b'Michael', b'Tracy', b'Sarah']:
    # 发送数据
    s.send(data)
    print(s.recv(1024).decode('utf-8'))

s.send(b'exit')
s.close()

服务器:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# tcp 服务器端编程
import socket,threading,time

def tcplink(sock, addr):
    print('Accept new connection from %s:%s...' % addr)
    sock.send(b'Welcome!')
    while True:
        data = sock.recv(1024)
        time.sleep(1)
        if not data or data.decode('utf-8') == 'exit':
            break
        sock.send(('Hello, %s!' % data.decode('utf-8')).encode('utf-8'))
    sock.close()
    print('Connection from %s:%s closed.' % addr)

# 服务器程序
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 监听端口
s.bind(('127.0.0.1', 9998))
s.listen(5)
print('Waiting for connection...')

while True:
    # 接受一个新连接
    sock,addr = s.accept()
    # 创建新线程来处理 TCP 连接
    t = threading.Thread(target=tcplink, args=(sock,addr))
    t.start()