#client.py
importosimportsignalfrom socket import *
from tkinter import *
from settings import *
from select importselectfrom threading importThreadfrom time importctime, sleepfrom tkinter.scrolledtext importScrolledTextfrom multiprocessing importProcess, Pipe, Valuefrom tkinter.messagebox importshowerror, showinfodefterminal():'实现终端操作'shm_terminal_pid.value=os.getpid()#开启客户端连接
c =socket()try:
c.connect(ADDR)except:#如果无法连接到客户端
os.kill(shm_gui_pid.value, signal.SIGKILL)print('Failed to connect to server')
os._exit(0)print('Connected to', ADDR)#IO多路复用,监听服务端通信以及保持与gui的通信
rlist =[c, pipe_terminal, pipe_validate_terminal]
wlist=[]
xlist=[]#服务器关闭信号
flag =FalsewhileTrue:ifflag:break
#阻塞等待IO事件
try:
rs, ws, xs=select(rlist, wlist, xlist)exceptKeyboardInterrupt:#如果客户端ctrl-c退出程序
for r inrlist:
r.close()break
for r inrs:if r isc:#接收服务端的信息
print('IO: client')
data=c.recv(buffersize)if notdata:print('服务器关闭了')for r inrlist:
r.close()
flag=Trueelse:#如果发来的是登录验证结果信息
ifdata.decode().startswith(login_code):print(data.decode())
status_code= data.decode().split(' ')[1]if status_code == 'Success':
pipe_validate_terminal.send(login_code)else:
pipe_validate_terminal.send('bad')#如果发来的消息是服务器退出消息
elif data.decode() ==exit_code:
pipe_gui.send('管理员关闭了服务器')
os.kill(shm_gui_pid.value, signal.SIGKILL)
os._exit(0)else:print(data.decode())#将信息发送给pipe_gui
pipe_terminal.send(data.decode())elif r ispipe_terminal:#接收pipe_gui的信息
print('IO: pipe_terminal')
data=pipe_terminal.recv()#并把消息发送给服务端
c.send(data.encode())elif r ispipe_validate_terminal:#验证管道
data =pipe_validate_terminal.recv()
c.send(data.encode())defgui():'实现图形化界面操作'shm_gui_pid.value=os.getpid()#登录界面
login()
main=Tk()
main.title('Chatroom -' +curuser)
ent= Entry(main, width=100)
cnt=ScrolledText(main)
cnt.pack(expand=True, fill=BOTH)
ent.pack(expand=True, fill=BOTH)
ent.focus()
main.bind('', lambdaevent: write(widgets))
widgets={}
widgets['ent'] =ent
widgets['cnt'] =cnt#开启一个线程,监听pipe_terminal传过来的信息
thread_bridge = Thread(target=bridge, args=(widgets, ))
thread_bridge.start()
main.protocol('WM_DELETE_WINDOW', exit_main)
mainloop()
pipe_gui.close()
thread_bridge.join()defexit_main():
data= ctime() + '\n' + curuser + ':' + '退出了聊天室\n'pipe_gui.send(data)print(data)
data= logout_code + ' ' +curuser
pipe_validate_gui.send(data)print(data)
sleep(0.1)
os.kill(shm_terminal_pid.value, signal.SIGKILL)
os._exit(0)defbridge(widgets):#监听与pipe_terminal的通信,将获得的信息显示在gui上
whileTrue:print('IO: pipe_gui')
data=pipe_gui.recv()print(data)
widgets['cnt'].insert(END, data)defwrite(widgets):print('Gui Event')#打印ent文本到cnt文本框中去
data = ctime() + '\n' + curuser + ':' + widgets['ent'].get() + '\n'widgets['cnt'].insert(END, data)
widgets['ent'].delete(0, END)#将信息发送给pipe_terminal
pipe_gui.send(data)deflogin():
top=Tk()
top.title('chatroom - login')
Label(top, text='username:').grid(row=0, column=0)
ent=Entry(top)
ent.grid(row=0, column=1)
ent.focus()
btn= Button(top, text='confirm', command=lambda: validate(top, ent))
btn.grid(row=1, columnspan=2)
top.bind('', lambdaevent: validate(top, ent))
top.protocol('WM_DELETE_WINDOW', exit_login)
mainloop()defvalidate(top, ent):print('validate')if notent.get():
showerror('Login Error', 'Empty Username!')else:
username=ent.get()#将用户名发送给terminal,再发送给服务器以验证
pipe_validate_gui.send(login_code + ' ' +username)
data=pipe_validate_gui.recv()if data ==login_code:globalcuruser
curuser=username
showinfo('Login Successful', 'Welcome to Internet Chatroom.')
top.destroy()else:
showerror('Login Failure', 'Username already exists!')
ent.delete(0, END)defexit_login():
os._exit(0)if __name__ == '__main__':#当前用户名
curuser = ''
#共享内存
shm_gui_pid = Value('i', 0)
shm_terminal_pid= Value('i', 0)#创建管道,实现终端与图形化界面的通信
pipe_terminal, pipe_gui =Pipe()#创建管道,实现login->client->server的登录验证
pipe_validate_gui, pipe_validate_terminal =Pipe()#创建两个进程,分别实现终端和图形化界面操作
process_terminal = Process(target=terminal)
process_gui= Process(target=gui)#开始进程
process_terminal.start()
process_gui.start()#回收进程
process_terminal.join()
process_gui.join()