Socket聊天软件编程

服务器端代码

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.tp.apply_async(func=self.running_true)
		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)

															  #sticky=E:确定组件在格子的位置
		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,
		}	
		# timeout = 5
		# socket.setdefaulttimeout(timeout)
		self.client =socket.socket(socket.AF_INET,socket.SOCK_STREAM)		 
		#socket.settimeout(self.client)

		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)
					# chat()
				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()

猜你喜欢

转载自blog.csdn.net/weixin_44169868/article/details/85093873
今日推荐