Python-TCP服务端程序开发
Posted 礁之
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python-TCP服务端程序开发相关的知识,希望对你有一定的参考价值。
文章目录
一. TCP服务端程序开发
"""
主动套接字: 可以收发信息的套接字
被动套接字: 不能收发信息
TCP服务端的流程:
1. 创建socket对象
2. 绑定, 固定服务器的ip和端口
3. 设置监听, 将主动套接字变成被动套接字, 可以接收新的客户端连接,
4. 阻塞等待客户端的连接, 有客户端连接, 会返回一个新的socket, 用来和客户端通信, 原始socket会监听新的创建的socket
5. 新的socket接收信息
6. 新的socket发送信息
7. 新的socket关闭, 表示不能通信的 监听的socket 关闭了, 不能接收新的客户端连接
注意: 其中 5,6 步骤是可以重复执行的
"""
import socket
if __name__ == '__main__':
# 1. 创建socket对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2. 绑定, 固定服务器的ip和端口 socket对象.bind((IP地址, 元组)) 注意是元组
# server_socket.bind(("192.168.218.1", 8355))
server_socket.bind(("", 8355)) # 收不到的话可能是端口被占用了
# 3. 设置监听, 将主动套接字变成被动套接字, 可以接收新的客户端连接 socket对象.listen(同时连接服务器的最大数量) 连接成功之后就不会占用连接名额
server_socket.listen(128)
print("服务等待连接中......")
# 4. 阻塞等待客户端的连接, 有客户端连接, 会返回一个新的socket, 用来和客户端通信, 原始socket会监听新的创建的socket
# socket对象.accept() 返回一个元组, (新的socket, (客户端的ip, 端口)) 注意是两层元组
new_socket, ip_port = server_socket.accept() # 拆分赋值变量
print(f"客户端ip_port 已经连接了......")
# 5. 新的socket接收信息, 使用新的socket进行接收
buf = new_socket.recv(4096)
print("接收到的信息为", buf.decode("gbk"))
# 6. 新的socket发送信息
send_data = "信息已经收到......".encode("gbk")
new_socket.send(send_data)
# 7. 新的socket关闭, 表示不能通信的 监听的socket 关闭了, 不能接收新的客户端连接, 创建的socket也关闭
new_socket.close()
server_socket.close()
二. 端口复用
"""
问题: 在进行连接后立即执行, 会报错显示端口已经被使用
正常情况下, 服务器的代码是永远不会关闭的, 就不会出现整个问题
但是特殊情况下, 启动服务器后, 运行一次, 马上关闭再次运行, 就会出现整个bug, 端口必须要等待 30s - 2min后才能使用
解决方案:
1. 换个端口(显然不太现实, 因为客户端也需要不停的换端口)
2. 代码解决, 代码实现,让程序关闭之后, 可以立即使用整个端口, 即 端口复用
"""
import socket
if __name__ == '__main__':
# 1. 创建socket对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置端口复用
# level 设置哪个级别的 socket, socket.SOL_SOCKET 表示当前socket
# optname 设置什么内容(权限) socket.SO_REUSEADDR 端口复用
# value 设置为什么值 True
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 2. 绑定, 固定服务器的ip和端口 socket对象.bind((IP地址, 元组)) 注意是元组
# server_socket.bind(("192.168.218.1", 8355))
server_socket.bind(("", 8355)) # 收不到的话可能是端口被占用了
# 3. 设置监听, 将主动套接字变成被动套接字, 可以接收新的客户端连接 socket对象.listen(同时连接服务器的最大数量) 连接成功之后就不会占用连接名额
server_socket.listen(128)
print("服务等待连接中......")
# 4. 阻塞等待客户端的连接, 有客户端连接, 会返回一个新的socket, 用来和客户端通信, 原始socket会监听新的创建的socket
# socket对象.accept() 返回一个元组, (新的socket, (客户端的ip, 端口)) 注意是两层元组
new_socket, ip_port = server_socket.accept() # 拆分赋值变量
print(f"客户端ip_port 已经连接了......")
# 5. 新的socket接收信息, 使用新的socket进行接收
buf = new_socket.recv(4096)
print("接收到的信息为", buf.decode("gbk"))
# 6. 新的socket发送信息
send_data = "信息已经收到......".encode("gbk")
new_socket.send(send_data)
# 7. 新的socket关闭, 表示不能通信的 监听的socket 关闭了, 不能接收新的客户端连接, 创建的socket也关闭
new_socket.close()
server_socket.close()
三. 判断客户端程序是否断开
"""
问题: 在客户端没有发送消息的情况下直接断开, 后续的代码还会继续执行
解决方案:
判断客户端程序是否已经断开
"""
import socket
if __name__ == '__main__':
# 1. 创建socket对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置端口复用
# level 设置哪个级别的 socket, socket.SOL_SOCKET 表示当前socket
# optname 设置什么内容(权限) socket.SO_REUSEADDR 端口复用
# value 设置为什么值 True
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 2. 绑定, 固定服务器的ip和端口 socket对象.bind((IP地址, 元组)) 注意是元组
# server_socket.bind(("192.168.218.1", 8355))
server_socket.bind(("", 8355)) # 收不到的话可能是端口被占用了
# 3. 设置监听, 将主动套接字变成被动套接字, 可以接收新的客户端连接 socket对象.listen(同时连接服务器的最大数量) 连接成功之后就不会占用连接名额
server_socket.listen(128)
print("服务等待连接中......")
# 4. 阻塞等待客户端的连接, 有客户端连接, 会返回一个新的socket, 用来和客户端通信, 原始socket会监听新的创建的socket
# socket对象.accept() 返回一个元组, (新的socket, (客户端的ip, 端口)) 注意是两层元组
new_socket, ip_port = server_socket.accept() # 拆分赋值变量
print(f"客户端ip_port 已经连接了......")
# 5. 新的socket接收信息, 使用新的socket进行接收
# 当对方的 socket close断开 后,自己的 socket 不再进行阻塞, recv接收的内容是空的, 长度为0
buf = new_socket.recv(4096)
if buf:
print("接收到的信息为", buf.decode("gbk"))
# 6. 新的socket发送信息
send_data = "信息已经收到......".encode("gbk")
new_socket.send(send_data)
else:
print(f"客户端ip_port已经断开连接......")
# 7. 新的socket关闭, 表示不能通信的 监听的socket 关闭了, 不能接收新的客户端连接, 创建的socket也关闭
new_socket.close()
server_socket.close()
四. 多任务版本
"""
在客户端连接后会创建新的socket
"""
import socket
import threading
def handle_client_request(n_socket, client_ip_port):
# 5. 新的socket接收信息, 使用新的socket进行接收
# 当对方的 socket close断开 后,自己的 socket 不再进行阻塞, recv接收的内容是空的, 长度为0
while True: # 这里也需要循环
buf = n_socket.recv(4096)
if buf:
print(f"接收到client_ip_port的信息为", buf.decode("gbk"))
# 6. 新的socket发送信息
send_data = "信息已经收到......".encode("gbk")
n_socket.send(send_data)
else:
print(f"客户端client_ip_port已经断开连接......")
break # 关闭后跳出循环, 关闭socket
# 7. 新的socket关闭, 表示不能通信的 监听的socket 关闭了, 不能接收新的客户端连接, 创建的socket也关闭
n_socket.close()
if __name__ == '__main__':
# 1. 创建socket对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置端口复用
# level 设置哪个级别的 socket, socket.SOL_SOCKET 表示当前socket
# optname 设置什么内容(权限) socket.SO_REUSEADDR 端口复用
# value 设置为什么值 True
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 2. 绑定, 固定服务器的ip和端口 socket对象.bind((IP地址, 元组)) 注意是元组
# server_socket.bind(("192.168.218.1", 8355))
server_socket.bind(("", 8355)) # 收不到的话可能是端口被占用了
# 3. 设置监听, 将主动套接字变成被动套接字, 可以接收新的客户端连接 socket对象.listen(同时连接服务器的最大数量) 连接成功之后就不会占用连接名额
server_socket.listen(128)
print("服务等待连接中......")
while True: # 循环等待客户端的消息
# 4. 阻塞等待客户端的连接, 有客户端连接, 会返回一个新的socket, 用来和客户端通信, 原始socket会监听新的创建的socket
# socket对象.accept() 返回一个元组, (新的socket, (客户端的ip, 端口)) 注意是两层元组
new_socket, ip_port = server_socket.accept() # 拆分赋值变量
print(f"客户端ip_port 已经连接了......")
# 创建线程, 执行任务
sub_thread = threading.Thread(target=handle_client_request, args=(new_socket, ip_port))
# 启动线程
sub_thread.start()
server_socket.close() # 关闭监听的 socket 注意不要写在循环里面
以上是关于Python-TCP服务端程序开发的主要内容,如果未能解决你的问题,请参考以下文章