服务器端代码
import socket
import pickle
import _pickle
import copy
from threading import Thread
import time
class TcpServer:
def __init__(self):
self.server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
self.server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
self.server.setblocking(0)
self.server_ip = ''
self.server_port = 55555
self.run_thread = None
self.send_user_thread = None
self.client_dict = {}
self.old_online_client = {}
self.new_online_client = {}
def send_onlie_user(self):
msg_online_user = {
'flag_user':None,
'online_user_dict':self.new_online_client,
}
print(msg_online_user)
for client_f in self.client_dict:
try:
client_f.send(pickle.dumps(msg_online_user))
except Exception as e:
print(e)
else:
print('发送成功')
def get_online_user(self):
while True:
time.sleep(5)
print('收集在线用户...')
self.new_online_client = {}
for client in self.client_dict:
user_account = self.client_dict[client]['user_info']['user_account']
user_nickname = self.client_dict[client]['user_info']['user_nickname']
if user_account and user_nickname:
self.new_online_client[user_account] = user_nickname
else:
if self.old_online_client == self.new_online_client:
continue
print('正在刷新在线用户...')
self.send_onlie_user()
self.old_online_client = self.new_online_client
def run(self):
print('Server open ...')
while True:
try:
try:
client,self.client_addr = self.server.accept()
except BlockingIOError:
pass
else:
client.setblocking(0)
print('[%s] Already Connect...'%(self.client_addr,))
self.client_dict[client] = {
'user_info':{
'user_account':None,
'user_nickname':None,
},
'user_msg':{
'user_to':None,
'user_massage':None,
},
}
client_dict_bak = copy.copy(self.client_dict)
for client in client_dict_bak:
if client in self.client_dict:
try:
self.recv_data = pickle.loads(client.recv(1024))
except BlockingIOError:
pass
except _pickle.UnpicklingError:
print('[E] 接收到无效数据')
del self.client_dict[client]
client.close()
except EOFError:
print('用户断开..')
del self.client_dict[client]
client.close()
except ConnectionResetError:
print('用户断开..')
del self.client_dict[client]
client.close()
else:
if 'only' in self.recv_data:
self.check()
if 'massage' in self.recv_data:
from_account = self.client_dict[client]['user_info']['user_account']
from_nickname = self.client_dict[client]['user_info']['user_nickname']
if not from_account and not from_nicknmae:
print('违规用户..')
del self.client_dict[client]
client.close()
else:
to_msg = self.recv_data['to_msg']
to_account = self.recv_data['to_account']
print('[%s]--->[%s]\n%s'%(from_account,to_account,to_msg))
for client_recv in self.client_dict:
user_account = self.client_dict[client_recv]['user_info']['user_account']
if user_account == to_account:
msg_forward = {
'to_msg':to_msg,
'from_account':from_account,
'from_nickname':from_nickname,
}
client_recv.send(pickle.dumps(msg_forward))
break
if 'alive' in self.recv_data:
print('我还活着...')
ack = {
'ack':None,
}
client_recv.send(pickle.dumps(ack))
except KeyboardInterrupt:
break
del self
def check(self):
first_check_repeat = {
'only':None,
'flag':None,
'm':None,
}
client_account_list = []
for client in self.client_dict:
user_account = self.client_dict[client]['user_info']['user_account']
if user_account:
client_account_list.append(user_account)
client_account = self.recv_data['account']
client_nickname = self.recv_data['nickname']
if str(client_account) in client_account_list:
first_check_repeat['flag'] = False
print('用户[%s]已被踢出服务器...'%(self.client_addr,))
first_check_repeat['m'] = '账户已被登陆,换个试试吧'
client.send(pickle.dumps(first_check_repeat))
del self.client_dict[client]
client.close()
else:
self.client_dict[client]['user_info']['user_account'] = client_account
self.client_dict[client]['user_info']['user_nickname'] = client_nickname
print(self.client_dict[client])
first_check_repeat['flag'] = True
client.send(pickle.dumps(first_check_repeat))
def __call__(self):
self.server.bind((self.server_ip,self.server_port))
self.server.listen(5)
self.run_thread = Thread(target=self.run)
self.send_user_thread = Thread(target=self.get_online_user)
self.run_thread.start()
self.send_user_thread.start()
def __del__(self):
if self.client_dict:
msg = {
'close':'服务器即将关闭!',
}
for client in self.client_dict:
client.send(pickle.dumps(msg))
client.close()
self.run_thread.join()
self.send_user_thread.join()
self.server.close()
def main():
s = TcpServer()
s()
if __name__ == '__main__':
main()
客户端代码
import pickle
from threading import Thread
import socket
from multiprocessing.pool import ThreadPool
import tkinter
import tkinter.messagebox as messagebox
import time
class Chat:
def __init__(self,client,nickname):
self.root = tkinter.Tk()
self.client = client
self.nickname = nickname
self.root.title('欢迎你:%s'%(nickname))
self.frame_left_top = tkinter.Frame(width=380,height=270)
self.frame_left_center = tkinter.Frame(width=380,height=100)
self.frame_left_bottom = tkinter.Frame(width=380,height=30)
self.frame_right = tkinter.Frame(width=170,height=400)
self.online_user_list = tkinter.Listbox(self.frame_right,width=170,height=22)
self.online_user_list.bind('<Double-Button-1>',self.get_talk_user)
self.msg_list_text = tkinter.Text(self.frame_left_top)
self.msg_list_text.tag_configure('green',foreground='#008B00')
self.msg_send_text = tkinter.Text(self.frame_left_center)
self.msg_send_button = tkinter.Button(self.frame_left_bottom,text='发送',command=self.send_user_msg)
self.frame_left_top.grid(row=0,column=0,padx=2, pady=5)
self.frame_left_center.grid(row=1,column=0, padx=2,pady=5)
self.frame_left_bottom.grid(row=2,column=0)
self.frame_right.grid(row=0,column=1,rowspan=3,padx=5,pady=5)
self.frame_left_top.grid_propagate(0)
self.frame_left_center.grid_propagate(0)
self.frame_left_bottom.grid_propagate(0)
self.frame_right.grid_propagate(0)
self.msg_list_text.grid()
self.msg_send_text.grid()
self.msg_send_button.grid(sticky=tkinter.E)
self.online_user_list.grid()
self.tp = ThreadPool(5)
self.talk_user = ''
self.running = True
self.tp.apply_async(func=self.recv_msg)
self.root.mainloop()
def recv_msg(self):
while True:
try:
repeat_ = pickle.loads(self.client.recv(1024))
except ConnectionResetError:
messagebox.showerror(title='抱歉',message='与服务器失去了连接!')
break
except Exception as e:
print(e)
messagebox.showerror(title='抱歉',message='服务器出问题了!')
break
else:
if 'flag_user' in repeat_:
print('接收到了用户列表')
user_dict = repeat_['online_user_dict']
self.tp.apply_async(self.refer_user_list,args=(user_dict,))
if 'to_msg' in repeat_:
print('收到消息')
to_msg = repeat_['to_msg']
from_account = repeat_['from_account']
from_nickname = repeat_['from_nickname']
self.tp.apply_async(self.show_online_user,args=(from_account,from_nickname,to_msg))
if 'ack' in repeat_:
print('server alive ..')
self.running = True
if 'close' in repeat_:
msg = repeat_['close']
messagebox.showerror(title='抱歉',message=msg)
break
def show_online_user(self,from_account,from_nickname,to_msg):
msgcontext = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime())+'\n'
self.msg_list_text.insert(tkinter.END,'%s(%s)%s'%(from_account,from_nickname,msgcontext))
self.msg_list_text.insert(tkinter.END,to_msg)
def refer_user_list(self,user_dict):
self.online_user_list.delete(0,tkinter.END)
for user_account in user_dict:
self.online_user_list.insert(
tkinter.END,
'%s:%s'%(user_account,user_dict[user_account])
)
def check_alive(self):
while True:
time.sleep(5)
server_alive = {
'alive':None,
}
self.client.send(pickle.dumps(server_alive))
def running_true(self):
print('开启服务器检测...',self.running)
while True:
time.sleep(5)
if self.running:
self.runing = False
self.check_alive()
else:
messagebox.showerror(title='抱歉',message='服务器出问题了!')
def get_talk_user(self,event):
name = self.online_user_list.get(self.online_user_list.curselection()[0])
self.talk_user = name.split(':')[0]
def send_user_msg(self):
print('发送消息')
if not self.talk_user:
return
send_msg = self.msg_send_text.get('0.0',tkinter.END)
self.msg_send_text.delete('0.0',tkinter.END)
msg = {
'massage':None,
'to_msg':send_msg,
'to_account':self.talk_user,
}
try:
self.client.send(pickle.dumps(msg))
except ConnectionResetError:
messagebox.showerror(title='抱歉',message='与服务器失去了连接!')
except ConnectionAbortedError:
messagebox.showerror(title='抱歉',message='服务器已关闭!')
else:
msgcontext = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime())+'\n'
self.msg_list_text.insert(tkinter.END,msgcontext,'green')
self.msg_list_text.insert(tkinter.END,send_msg)
class Login:
def __init__(self):
self.root = tkinter.Tk()
self.root.title('登陆')
self.root.resizable(height=False,width=False)
self.root_width = 270
self.root_height = 110
self.screen_width = self.root.winfo_screenwidth()
self.screen_height = self.root.winfo_screenheight()
self.root.geometry('%dx%d+%d+%d'%(
self.root_width,
self.root_height,
(self.screen_width - self.root_width) / 2,
(self.screen_height - self.root_height) /2 ,
))
self.lable_account = tkinter.Label(self.root,text='Account:')
self.entry_account = tkinter.Entry(self.root)
self.lable_passwd = tkinter.Label(self.root,text='Password:')
self.entry_passwd = tkinter.Entry(self.root)
self.lable_nickname = tkinter.Label(self.root,text='昵称:')
self.entry_nickname = tkinter.Entry(self.root)
self.lable_account.grid(row=0,column=0,padx=30,sticky=tkinter.E)
self.entry_account.grid(row=0,column=1)
self.lable_passwd.grid(row=1,column=0)
self.entry_passwd.grid(row=1,column=1)
self.lable_nickname.grid(row=2,column=0)
self.entry_nickname.grid(row=2,column=1)
self.login_button = tkinter.Button(self.root,text='登陆',command=self.check_user)
self.cancel_button = tkinter.Button(self.root,text='取消',command=self.cancel_login)
self.login_button.grid(row=3,column=1)
self.cancel_button.grid(row=3,column=0)
def check_user(self):
account = self.entry_account.get()
password = self.entry_passwd.get()
self.nickname = self.entry_nickname.get()
check = {
'only':None,
'account':account,
'password':password,
'nickname':self.nickname,
}
self.client =socket.socket(socket.AF_INET,socket.SOCK_STREAM)
try:
self.client.connect(('192.168.1.200',55555))
self.client.send(pickle.dumps(check))
only_check = pickle.loads(self.client.recv(1024))
except Exception as e:
print(e)
messagebox.showerror(title='抱歉',message='服务器错误!')
else:
if 'only' in only_check:
if only_check['flag']:
messagebox.showinfo(title='恭喜',message='登陆成功!')
self.root.destroy()
chat = Chat(self.client,self.nickname)
else:
msgg = only_check['m']
messagebox.showwarning(title='欸呀呀...',message=msgg)
del self.client
def cancel_login(self):
self.root.destroy()
def __call__(self):
self.root.mainloop()
def main():
loginroot = Login()
loginroot()
if __name__ == '__main__':
main()