TCP 服务器实现
import socket
def tcp_server():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_address = ('localhost', 8888)
server_socket.bind(server_address)
server_socket.listen(1)
print('Server is listening on {}:{}'.format(*server_address))
try:
while True:
client_socket, client_address = server_socket.accept()
print('Accepted connection from {}:{}'.format(*client_address))
try:
while True:
data = client_socket.recv(1024)
if data:
print('Received: {}'.format(data.decode('utf - 8')))
client_socket.sendall(data)
else:
break
finally:
client_socket.close()
print('Connection with {}:{} closed'.format(*client_address))
finally:
server_socket.close()
if __name__ == '__main__':
tcp_server()
TCP 客户端实现
import socket
def tcp_client():
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('localhost', 8888)
client_socket.connect(server_address)
try:
message = 'Hello, Server!'
client_socket.sendall(message.encode('utf - 8'))
data = client_socket.recv(1024)
print('Received: {}'.format(data.decode('utf - 8')))
finally:
client_socket.close()
if __name__ == '__main__':
tcp_client()
操作处理
- 连接建立
- 服务器:使用
socket.socket()
创建套接字对象,指定地址族 AF_INET
(IPv4)和套接字类型 SOCK_STREAM
(TCP)。通过 setsockopt
设置 SO_REUSEADDR
选项,允许地址重用,避免 Address already in use
错误。调用 bind
方法绑定服务器地址和端口,然后使用 listen
方法开始监听连接,参数指定最大连接数。
- 客户端:同样创建套接字对象,使用
connect
方法连接到服务器的地址和端口。
- 数据传输
- 服务器:在接受客户端连接后,进入一个循环,使用
recv
方法接收客户端发送的数据,recv
方法的参数指定接收缓冲区的大小。接收到数据后进行处理(这里是回显),使用 sendall
方法将数据发送回客户端。
- 客户端:使用
sendall
方法向服务器发送数据,然后使用 recv
方法接收服务器回显的数据。
- 关闭连接
- 服务器:当客户端关闭连接或没有数据可读时,服务器关闭与该客户端的连接,通过调用
client_socket.close()
。当服务器程序结束时,关闭服务器套接字 server_socket.close()
。
- 客户端:在完成数据传输后,调用
client_socket.close()
关闭连接。
常见错误及解决办法
- Address already in use
- 原因:服务器程序上次运行后,端口没有及时释放。
- 解决办法:在服务器创建套接字后,设置
SO_REUSEADDR
选项,如上述代码中的 server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
。
- Connection refused
- 原因:客户端尝试连接时,服务器可能未启动,或者服务器监听的地址和端口与客户端连接的不一致。
- 解决办法:确保服务器已正确启动并监听指定的地址和端口,检查客户端连接的地址和端口是否与服务器一致。
- Timeout
- 原因:在规定时间内未完成连接建立或数据传输。
- 解决办法:可以适当调整连接超时和接收超时时间,通过
setsockopt
设置 SO_RCVTIMEO
和 SO_SNDTIMEO
选项来设置接收和发送超时时间。例如:client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, 10)
(设置接收超时为 10 秒)。