如何运用python多线程实现UDP通信
最近在做通信与网络的课程实践,遇到了使用UDP实现socket编程,然而。。。我找不到使用多线程的代码!!!
其实有找到一个的但因为使用的是os块的pid函数,而本Windows系统表示不能使用这个函数,所以我只能自己改改改,终于写好了使用多线程实现UDP通信啦~
服务器:server.py
import socket
import threading
# 创建 UDP 套接字
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 设置端口复用
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 绑定地址
address = ('127.0.0.1', 8888)
server.bind(address)
userlist = {} # 此字典用于存放客户端的名字和地址
# 处理客户端请求的函数
def doRequest():
while True:
# 接收来自客户端的消息
msg, addr = server.recvfrom(1024)
msglist = msg.decode().split(' ') # 拆分数据,以空格为分隔
if msglist[0] == 'login': # 如果是进入聊天室请求
doLogin(msglist[1], addr)
# sendAZ()
elif msglist[0] == 'speak':
# msglist:['c','name','content']
content = ' '.join(msglist[2:]) # 获取完整发送内容
# 发送给其他所有成员
doChat(content, msglist[1])
elif msglist[0] == 'quit':
doQuit(msglist[1])
#发送A到Z
def sendAZ():
for i in range(65, 91):
message = '服务器:%s' % chr(i)
print('发送:%s' % chr(i))
server.sendto(message.encode(), address)
# 客户端退出处理函数
def doQuit(name):
message = '\n%s 退出了聊天室' % name
for u in userlist:
if u != name:
server.sendto(message.encode(), userlist[u])
else:
server.sendto('exit'.encode(), userlist[name])
# 从存储结构中删除
del userlist[name]
# 用于聊天的函数(把内容发送给其他成员)
def doChat(content, name):
message = '\n%s 说:%s' % (name, content)
for u in userlist:
if u != name: # 发给不是自身的所有客户端
server.sendto(message.encode(), userlist[u])
# 列表用字典存储{name,addr}
# 进入聊天室请求处理函数
def doLogin(name, addr):
# 判断姓名是否同名
if (name in userlist) : # 如果列表中已经存在此用户名
server.sendto('该用户已经存在!'.encode(), addr)
return # 函数结束,返回继续接收新的数据
# 同名不存在,发送信号给客户端,运行进入
server.sendto('OK'.encode(), addr)
# 通知所有人
message = '\n欢迎%s进入聊天室' % name
for u in userlist:
server.sendto(message.encode(), userlist[u]) # 全发
userlist[name] = addr # 加入到存储结构userlist字典中
print(userlist)
for i in range(65, 91):
message = '服务器:%s' % chr(i)
print('发送:%s' % chr(i))
server.sendto(message.encode(), userlist[name])
# 创建多线程,让子进程负责管理员喊话,父进程和客户端交互
t = threading.Thread(target=doRequest(), args=(server,))
t.start()
for client in userlist:
client.close()
print('-'*5+'服务器断开连接'+'-'*5)
客户端:client.py
import socket
import threading
address = ('127.0.0.1', 8888)
# 创建 UDP 套接字
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 接收用户输入,包装后发送给服务器
while True:
name = input('请输入姓名:')
message = 'login ' + name # 此处加入标记
client.sendto(message.encode(), address)
data, addr = client.recvfrom(1024)
if data.decode() == 'OK':
print('您已经进入聊天室...')
break
else: # 不允许进入
# 打印不允许进入的原因
print(data.decode())
def sendmsg():
# 发送消息给服务器,服务器群发给所有客户端
while True:
content = input('请发言(输入quit 退出):')
if content == 'quit':
message = 'quit ' + name
client.sendto(message.encode(), address)
print('退出')
client.close() # 子进程退出
# 包装消息
message = 'speak %s %s' % (name, content)
client.sendto(message.encode(), address)
def recvmsg():
while True:
message, addr = client.recvfrom(1024)
if message.decode() == 'exit': # 如果收到服务器此消息,父进程退出
# 关闭连接
print('退出')
client.close()
# 因为print覆盖了之前的input界面,在这里重新输出一遍
print(message.decode() + '\n请发言(quit退出):', end='')
send_thread = threading.Thread(target=sendmsg)
send_thread.start()
recv_thread = threading.Thread(target=recvmsg)
# 设置成为守护进程
recv_thread.setDaemon(True)
recv_thread.start()
send_thread.join()
# 关闭连接
print('-'*5+'服务器断开连接'+'-'*5)
client.close()
文中因为有老师要求的源代码自动给客户端发送A~Z,所以中间的一部分是当有新的客户端连上服务器后,服务器将自动发送A-Z给这个客户端。