python 实现 udp socket 编程的多线程问题
希望实现以下功能:
在点击“启动服务器”,即执行start函数时,开启监听线程,监听线程会用recvfrom()函数来监听数据报的到来。但是如果没有数据报过来,则其会阻塞在recvfromm()上。但是希望在没有数据报来的时候,可以继续主进程(会发送数据报的进程)的执行。
求问怎么做??
具体两个函数如下:(给出了前面主要的函数,剩下的一些省略了)
from tkinter import *
from time import sleep
from UserTable import *
from RoomTable import *
from ServerReceive import *
from socket import *
import pickle
import re
import string
import time
import threading
import pdb
用于建立服务端界面,建立监听线程,并处理本地命令
root = Tk()
root.geometry("600x400")
root.title("服务器端")
userroot = UserInfo(0, '', '', 0)
userTable = UserTable(userroot, None, 0) #用户列表
roomTable = RoomTable( ) #竞拍室列表
InRoom = None
text_contents=''
host = '127.0.0.1'
port =7890
nums = string.digits
发送按键对应的函数
def Send():
text_contents = text.get()
listbox.insert(END, text_contents)
text.delete(0,END)
cmd_choice(text_contents)
启动按键对应的函数,服务器端启动
def Start():
try:
global server
server = socket(AF_INET, SOCK_DGRAM) #启动服务端socket,默认端口7890
server.bind((host, port))
listbox.insert(END, "服务器端启动" )
#pdb.set_trace()
serverrec = ServerReceive(server, listbox, userTable, roomTable)
#pdb.set_trace()
serverrec.start() #建立监听线程???
serverrec.join()
except:
Exception, e
print(e)
退出按键对应的函数.服务器端退出
def Exit():
SendMsg("/msg 【系统消息】 服务器关闭!")
exit()
进行命令匹配的函数
def cmd_choice(text_contents):
m=re.match("/msg ", text_contents)
if m: #群发消息
SendMsg(text_contents)
else:
m=re.match("/list", text_contents) #列出某竞拍室情况
if m:
List()
else:
m=re.match("/kickout ", text_contents) #将某竞拍者踢出拍卖室
if m:
Kickout(text_contents)
else:
m=re.match("/opennewauction ", text_contents) #开通新竞拍室
if m:
Open(text_contents)
else:
m=re.match("/auctions", text_contents) #列出所有竞拍室情况
if m:
Auction()
else:
m=re.match("/enter ", text_contents) #加入某竞拍室
if m:
Enter(text_contents)
else:
m=re.match("/leave", text_contents) #离开某竞拍室
if m:
Leave()
else:
m=re.match("/close ", text_contents) #关闭某竞拍室
if m:
Close(text_contents)
else: #其他格式错误命令,弹出警告框??
listbox.insert(END, "\t命令输入错误!")
命令/msg [bidderID],群发和向指定用户发送消息
def SendMsg(text_contents):
lenmsg = len(text_contents)
if lenmsg == 4 or lenmsg == 5: #命令中没有发送内容,警告
listbox.insert(END, "未输入发送消息的内容!\n" )
return
i = 7
if text_contents[5] == "[" and text_contents[6] in nums: #对某一用户发送消息 查找用户ID
while text_contents[i] in nums:
i=i+1
if text_contents[i] != "]":
listbox.insert(END, "\t命令输入错误!" ) #未输入用户ID,提示错误
return
ID = text_contents[6:i] #提取用户ID
temp = userTable.findUser(ID)
if temp : #在用户列表中找到该用户??
if i+1 == lenmsg:
listbox.insert(END, "未输入发送消息的内容!\n" ) #命令中没有发送内容,警告
return
message = text_contents[i+1:] + "\n" #提取发送内容
try: #发送内容???
server.sendto(message, temp.addr, temp.port)
except:
Exception,e
print (e)
else:
listbox.insert(END, "没有该用户!\n" ) #未在用户列表中找到该用户,警告
return
else: #对所有用户群发消息
message = text_contents[i+1:] + "\n"
temp = userTable.root
while temp.next != None: #遍历用户列表并发送消息
temp = temp.next
try: #发送内容???
server.sendto(message, temp.addr, temp.port)
except:
Exception, e
print (e)
命令/list,列出某一竞拍室参加竞拍者的情况(必须已进入某一竞拍室)
def List():
————————————————————————————————————————————
监听线程如下:
import re
import string
import threading
import pickle
from tkinter import *
from socket import *
from UserTable import *
from RoomTable import *
import pdb
类ServerReceive 网络拍卖行服务端监听接收线程类
用于监听并接收客户端发送过来的数据包,并进行相应的处理
class ServerReceive(threading.Thread):
server = socket(AF_INET, SOCK_DGRAM)
addr=''
port=0
ADDR=(addr,port)
recvStr=''
newStr=''
root=UserInfo(0, '', '', 0)
userList = UserTable(root, None, 0) #用户列表
roomTable = RoomTable() #竞拍室列表
bufsize=512
user = UserInfo(0, '', '', 0) #用户信息
room = RoomInfo('', 0) #竞拍室信息
bidderID = 1 #分配的用户ID
listbox = None
def __init__(self, server, listbox, userList, roomTable):
super().__init__()
self.server = server
self.listbox = listbox #消息接收区域
self.userList = userList
self.roomTable = roomTable
#启动监听并接收数据包,并对数据包进行处理
def run(self):
pdb.set_trace()
#i=0
while True:
#if i >= 1:
#break
try:
self.recvStr, self.ADDR = self.server.recvfrom(self.bufsize) #提取数据报内容,用户IP地址,端口号
self.user = self.userList.findUser(self.addr, self.port) #在用户列表中查找该用户信息
#socket.settimeout(self.server)
self.recvStr = self.recvStr.decode('gb2312')
#i+= 1
m=re.match("/login ", self.recvStr)
if m: #登录服务器
self.Login(self.recvStr,self.ADDR)
else:
m=re.match("/exit", self.recvStr) #退出
if m:
self.Exit()
else:
if user == None: #未登录(此时不允许输入除登录、退出之外的命令)
self.NoLogin()
else:
m=re.match("/auctions", self.recvStr) #列出所有竞拍室情况
if m:
self.Auctions()
else:
m=re.match("/list", self.recvStr) #列出某竞拍室情况
if m:
self.List()
else:
m=re.match("/join ", self.recvStr) #加入某竞拍室
if m:
self.Join(self.recvStr)
else:
m=re.match("/bid ", text_contents) #出价
if m:
self.Bid(self.recvStr)
else:
m=re.match("/leave", self.recvStr) #离开某竞拍室
if m:
self.Leave()
else: #其他格式错误命令
self.ErrorCom()
except:
Exception,e
print(e)
#命令格式错误
def ErrorCom(self):
error = "命令输入错误!\n"
try: #发送内容???
self.server.sendto(error, self.addr, self.port)
except:
Exception, e
print (e)
#命令/login bidderName,用bidderName登录服务器。服务方给该用户分配一个唯一标识bidderID
def Login(self, recvStr,ADDR1):
pdb.set_trace()
if len(recvStr) == 7: #命令不包含用户名
newStr = "未输入用户名!\n"
else:
name = recvStr[7:]
print(name)
if self.userList.findUser1(name) == None and self.user == None:
self.user = UserInfo(self.bidderID, name, self.addr, self.port) #加入新用户信息
self.userList.addUser(self.user)
self.listbox.insert(END, "用户 " + name + " 连接成功! " + str(ADDR1)+ "\n")
self.bidderID+= 1
newStr ="【系统消息】 您好,"+ name + ",欢迎来到网络拍卖行" + "! 您的用户ID: " + str(self.bidderID) + "\n" #返回欢迎信息
else:
if self.userList.findUser(self.addr, self.port)!= None: #该IP地址和端口已经登录过用户
newStr = "不能登录多个用户!\n"
else:
if self.userList.findUser(name)!= None: #用户列表中已存在该用户名
newStr = "不能重复登录!\n";
try: #发送内容???
self.server.sendto(newStr, self.addr, self.port)
except:
Exception, e
print (e)