多任务版TCP服务端程序开发

分析

当客户端和服务端建立连接成功,创建子线程,使用子线程专门处理客户端的请求,防止主线程阻塞

 

示例

服务端

复制代码
 1 import socket
 2 import threading
 3 
 4 
 5 # 处理客户端函数
 6 def handle_client(conn_socket, ip_port):
 7     try:
 8         while True:
 9             # 5.接收数据
10             recv_data = conn_socket.recv(1024)
11             if not recv_data:  # 一般是客户端主动端口或网络问题导致自动端口
12                 break
13             else:
14                 print("接收到的数据:", recv_data.decode('utf-8'))
15                 # 6.发送数据
16                 conn_socket.send("客户端你的数据我收到了".encode())
17     except socket.error as e:
18         print("处理客户端数据发生异常,异常信息:{}", e)
19     finally:
20         if conn_socket is not None:
21             print("关闭客户端:", ip_port)
22             conn_socket.close()  # 7.关闭套接字
23 
24 
25 # 1 使用循环接收客户端的连接请求
26 if __name__ == '__main__':
27     # 1.创建服务端套接字对象
28     tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
29     # 设置端口复用即设置套接字的SO_REUSEADDR选项为True。
30     # 当设置SO_REUSEADDR选项为True时,表示允许在同一端口上重用本地地址。具体来说,它允许一个套接字对象再次绑定到一个已经处于TIME_WAIT状态的本地地址和端口,通常用于解决"Address already in use"错误。
31     tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
32     # 2. 绑定指定的IP地址和端口号
33     # tcp_server_socket.bind(("172.16.62.136", 8888))
34     # 如果bind中的参数第一个ip地址元素设置为"",默认为本机ip地址即所有本地上的所有IP
35     tcp_server_socket.bind(("", 8080))
36     # 3.设置监听 128:代表服务端等待排队连接的最大数量
37     tcp_server_socket.listen(128)
38 
39     while True:
40         # 4.等待接受客户端的连接请求 accept阻塞等待 返回一个用以和客户端通socket,客户端的地址
41         conn_socket, ip_port = tcp_server_socket.accept()
42         print("客户端地址:", ip_port)
43         print("ip_port的类型:", type(ip_port))
44 
45         # 使用多线程去接收多个客户端的请求
46         sub_thread = threading.Thread(target=handle_client, args=(conn_socket, ip_port))
47         sub_thread.start()
48 
49     tcp_server_socket.close()
复制代码

 

客户端

复制代码
 1 '''
 2 在使用Socket客户端时,还需要考虑以下几点最佳实践:
 3     1. 使用异常处理:Socket操作可能会抛出异常,例如连接错误或数据传输错误。因此,在使用Socket客户端时,应该使用适当的异常处理来捕获和处理这些异常。
 4     2. 关闭连接:在不再使用Socket连接时,应该及时关闭连接,以释放系统资源。
 5     3. 数据编码:在发送和接收数据时,需要将数据进行编码和解码,通常可以使用encode()和decode()方法将字符串转换为字节流和字节流转换为字符串。
 6     4. 错误处理:尽管Socket提供了可靠的网络通信,但仍然可能发生错误,例如连接超时或服务器无响应。在使用Socket客户端时,应该考虑这些错误情况,并采取相应的错误处理措施。
 7 '''
 8 
 9 import socket
10 
11 
12 def send_request(client_socket, request):
13     client_socket.sendall(request.encode('utf-8'))
14     response = client_socket.recv(1024).decode('utf-8')
15     return response
16 
17 
18 def main():
19     client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
20     server_address = ('localhost', 8080)
21     client_socket.connect(server_address)
22 
23     try:
24         while True:
25             request = input('Enter a request (q to quit): ')
26             if request == 'q':
27                 break
28             response = send_request(client_socket, request)
29             print('Response:', response)
30     finally:
31         client_socket.close()
32 
33 
34 if __name__ == '__main__':
35     main()
复制代码

通过netstat命令查看端口状况:

 端口复用

端口复用是指在一个主机上允许多个进程或应用程序同时监听同一个端口的能力。传统上,同一端口只能由一个进程绑定和监听,如果其他进程尝试绑定相同的端口,将导致冲突错误。

然而,使用端口复用技术,可以在允许多个应用程序共享同一端口,而不会引发冲突。这样可以提高系统资源的利用率,并简化应用程序的设计和部署。

在实现端口复用时,操作系统会为每个监听同一端口的进程分配一个唯一的标识符,称为套接字(Socket)。通过这种方式,操作系统可以正确地将数据包交给相应的进程或应用程序进行处理。

端口复用常用于以下场景:

  • 同一台服务器上运行多个网络服务,如Web服务器和FTP服务器等。
  • 在负载均衡环境中,多个服务器同时监听同一个端口,以实现请求的分发和负载均衡。
  • 快速重启或升级服务器程序,以保持服务的连续性,而无需停止其他正在使用该端口的进程。

在实现端口复用时,通常会使用套接字选项来指示操作系统是否允许端口复用,并设置相关参数。

需要注意的是,虽然端口复用可以提供更好的灵活性和效率,但也需要注意合理使用,以避免潜在的安全风险。

 

 

posted @   Allen_Hao  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示