网络编程案例多任务版TCP服务端程序开发
Posted ZSYL
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络编程案例多任务版TCP服务端程序开发相关的知识,希望对你有一定的参考价值。
案例-多任务版TCP服务端程序开发
案例-多任务版TCP服务端程序开发
学习目标
- 能够说出多任务版TCP服务端程序的实现过程
1. 需求
目前我们开发的TCP服务端程序只能服务于一个客户端,如何开发一个多任务版的TCP服务端程序能够服务于多个客户端呢?
完成多任务,可以使用 线程,比进程更加节省内存资源。
2. 具体实现步骤
- 编写一个TCP服务端程序,循环等待接受客户端的连接请求
- 当客户端和服务端建立连接成功,创建子线程,使用子线程专门处理客户端的请求,防止主线程阻塞
- 把创建的子线程设置成为守护主线程,防止主线程无法退出。
3. 多任务版TCP服务端程序的示例代码
import socket
import threading
# 处理客户端请求的任务
def handle_client_request(ip_port, new_client):
print("客户端的ip和端口号为:", ip_port)
# 5. 接收客户端的数据
# 收发消息都使用返回的这个新的套接字
# 循环接收客户端的消息
while True:
recv_data = new_client.recv(1024)
if recv_data:
print("接收的数据长度是:", len(recv_data))
# 对二进制数据进行解码变成字符串
recv_content = recv_data.decode("gbk")
print("接收客户端的数据为:", recv_content, ip_port)
send_content = "问题正在处理中..."
# 对字符串进行编码
send_data = send_content.encode("gbk")
# 6. 发送数据到客户端
new_client.send(send_data)
else:
# 客户端关闭连接
print("客户端下线了:", ip_port)
break
# 关闭服务与客户端套接字,表示和客户端终止通信
new_client.close()
if __name__ == '__main__':
# 1. 创建tcp服务端套接字
# AF_INET: ipv4 , AF_INET6: ipv6
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置端口号复用,表示意思: 服务端程序退出端口号立即释放
# 1. SOL_SOCKET: 表示当前套接字
# 2. SO_REUSEADDR: 表示复用端口号的选项
# 3. True: 确定复用
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 2. 绑定端口号
# 第一个参数表示ip地址,一般不用指定,表示本机的任何一个ip即可
# 第二个参数表示端口号
tcp_server_socket.bind(("", 9090))
# 3. 设置监听
# 128: 表示最大等待建立连接的个数
tcp_server_socket.listen(128)
# 4. 等待接受客户端的连接请求
# 注意点: 每次当客户端和服务端建立连接成功都会返回一个新的套接字
# tcp_server_socket只负责等待接收客户端的连接请求,收发消息不使用该套接字
# 循环等待接受客户端的连接请求
while True:
new_client, ip_port = tcp_server_socket.accept()
# 代码执行到此,说明客户端和服务端建立连接成功
# 当客户端和服务端建立连接成功,创建子线程,让子线程专门负责接收客户端的消息
sub_thread = threading.Thread(target=handle_client_request, args=(ip_port, new_client))
# 设置守护主线程,主线程退出子线程直接销毁
sub_thread.setDaemon(True)
# 启动子线程执行对应的任务
sub_thread.start()
# 7. 关闭服务端套接字, 表示服务端以后不再等待接受客户端的连接请求
# tcp_server_socket.close() # 因为服务端的程序需要一直运行,所以关闭服务端套接字的代码可以省略不写
执行结果:
客户端连接成功: ('172.16.47.209', 51528)
客户端连接成功: ('172.16.47.209', 51714)
hello1 ('172.16.47.209', 51528)
hello2 ('172.16.47.209', 51714)
4. 小结
- 编写一个TCP服务端程序,循环等待接受客户端的连接请求
while True:
service_client_socket, ip_port = tcp_server_socket.accept()
- 当客户端和服务端建立连接成功,创建子线程,使用子线程专门处理客户端的请求,防止主线程阻塞
while True:
service_client_socket, ip_port = tcp_server_socket.accept()
sub_thread = threading.Thread(target=handle_client_request, args=(service_client_socket, ip_port))
sub_thread.start()
- 把创建的子线程设置成为守护主线程,防止主线程无法退出。
while True:
service_client_socket, ip_port = tcp_server_socket.accept()
sub_thread = threading.Thread(target=handle_client_request, args=(service_client_socket, ip_port))
sub_thread.setDaemon(True)
sub_thread.start()
模拟QQ聊天-客户端
from socket import *
from threading import Thread
flag = True
def readMsg(client_socket):
while flag:
recv_data = client_socket.recv(1024)
print('收到:', recv_data.decode('utf-8'))
def writeMsg(client_socket):
global flag
while flag:
msg = input('>')
msg = user_name+'说:'+msg
client_socket.send(msg.encode('utf-8'))
if msg.endswith('bye'):
flag = False
break
# 创建客户端套接字对象
client_socket = socket(AF_INET, SOCK_STREAM)
user_name = input('请输入用户名:')
# 调用connect连接服务器
client_socket.connect(('192.168.0.108', 8888))
# 开启一个线程处理客户端的读取消息
t1 = Thread(target=readMsg, args=(client_socket,))
t1.start()
# 开启一个线程处理客户端的发送消息
t2 = Thread(target=writeMsg, args=(client_socket,))
t2.start()
t1.join()
t2.join()
client_socket.close()
模拟QQ聊天-服务端
from socket import *
from threading import Thread
# 存储所有的sockets
sockets = []
def main():
# 创建server_socket套接字对象
server_socket = socket(AF_INET, SOCK_STREAM)
# 绑定端口
server_socket.bind(('', 8888))
# 监听
server_socket.listen()
# 接收客户端的请求
server_socket.accept()
while True:
client_socket, client_info = server_socket.accept()
sockets.append(client_socket)
# 开启线程处理当前客户端的请求
t = Thread(target=readMsg, args=(client_socket,))
t.start()
def readMsg(client_socket):
# 读取客户端发送来的消息
while True:
recv_data = client_socket.recv(1024)
# 如果接收的消息中结尾是bye,则在客户端列表移除
if recv_data.decode('utf-8').endswidth('bye'):
sockets.remove(client_socket)
client_socket.close()
break
# 将消息发送给所有在线的客户端
# 遍历所有在线客户端列表
if len(recv_data) > 0:
for socket in sockets:
socket.send(recv_data)
if __name__ == '__main__':
main()
加油!
感谢!
努力!
以上是关于网络编程案例多任务版TCP服务端程序开发的主要内容,如果未能解决你的问题,请参考以下文章