python實現(xiàn)簡單聊天應(yīng)用 python群聊和點對點均實現(xiàn)
后續(xù)代碼更新和功能添加會提交到個人github主頁,有興趣可以一起來完善!
如果只是拿過去運行看結(jié)果,請注意平臺相關(guān)性以及python版本號,本示例開發(fā)運行平臺為win7x86_64 pycharm community,python版本號為3.5!!!
TALK IS CHEAP, SHOW YOU MY CODE:
客戶端
#coding:utf-8 ''' file:client.py.py date:2017/9/11 11:01 author:lockey email:lockey@123.com platform:win7.x86_64 pycharm python3 desc:p2p communication clientside ''' from socket import * import threading,sys,json,re #引入json模塊主要是為了數(shù)據(jù)的封裝傳輸,re的話是做一些合法性的驗證 HOST = '192.168.1.7' PORT=8022 BUFSIZE = 1024 ##緩沖區(qū)大小 1K ADDR = (HOST,PORT) myre = r"^[_a-zA-Z]\w{0,}" tcpCliSock = socket(AF_INET,SOCK_STREAM) #創(chuàng)建一個socket連接 userAccount = None #用戶登錄標(biāo)志,也用來記錄登錄的用戶名稱 def register(): #用戶注冊函數(shù) print(""" Glad to have you a member of us! """) accout = input('Please input your account: ') if not re.findall(myre, accout): print('Account illegal!') return None password1 = input('Please input your password: ') password2 = input('Please confirm your password: ') if not (password1 and password1 == password2): print('Password not illegal!') return None global userAccount userAccount = accout regInfo = [accout,password1,'register'] datastr = json.dumps(regInfo) tcpCliSock.send(datastr.encode('utf-8')) data = tcpCliSock.recv(BUFSIZE) data = data.decode('utf-8') if data == '0': print('Success to register!') return True elif data == '1': print('Failed to register, account existed!') return False else: print('Failed for exceptions!') return False def login(): #用戶登錄函數(shù) print(""" Welcome to login in! """) accout = input('Account: ') if not re.findall(myre, accout): print('Account illegal!') return None password = input('Password: ') if not password: print('Password illegal!') return None global userAccount userAccount = accout loginInfo = [accout, password,'login'] datastr = json.dumps(loginInfo) tcpCliSock.send(datastr.encode('utf-8')) data = tcpCliSock.recv(BUFSIZE) if data == '0': print('Success to login!') return True else: print('Failed to login in(user not exist or username not match the password)!') return False def addGroup(): #群組添加 groupname = input('Please input group name: ') if not re.findall(myre, groupname): print('group name illegal!') return None return groupname def chat(target): #進入聊天(群聊和點對點聊天可以選擇) while True: print('{} -> {}: '.format(userAccount,target)) msg = input() if len(msg) > 0 and not msg in 'qQ': if 'group' in target: optype = 'cg' else: optype = 'cp' dataObj = {'type': optype, 'to': target, 'msg': msg, 'froms': userAccount} datastr = json.dumps(dataObj) tcpCliSock.send(datastr.encode('utf-8')) continue elif msg in 'qQ': break else: print('Send data illegal!') class inputdata(threading.Thread): #用戶輸入選擇然后執(zhí)行不同的功能程序 def run(self): menu = """ (CP): Chat with individual (CG): Chat with group member (AG): Add a group (EG): Enter a group (H): For help menu (Q): Quit the system """ print(menu) while True: operation = input('Please input your operation("h" for help): ') if operation in 'cPCPCpcp': #進入個人聊天 target = input('Who would you like to chat with: ') chat(target) continue if operation in 'cgCGCgcG': #進入群聊 target = input('Which group would you like to chat with: ') chat('group'+target) continue if operation in 'agAGAgaG': #添加群組 groupName = addGroup() if groupName: dataObj = {'type': 'ag', 'groupName': groupName} dataObj = json.dumps(dataObj) tcpCliSock.send(dataObj.encode('utf-8')) continue if operation in 'egEGEgeG': #入群 groupname = input('Please input group name fro entering: ') if not re.findall(myre, groupname): print('group name illegal!') return None dataObj = {'type': 'eg', 'groupName': 'group'+groupname} dataObj = json.dumps(dataObj) tcpCliSock.send(dataObj.encode('utf-8')) continue if operation in 'hH': print(menu) continue if operation in 'qQ': sys.exit(1) else: print('No such operation!') class getdata(threading.Thread): #接收數(shù)據(jù)線程 def run(self): while True: data = tcpCliSock.recv(BUFSIZE).decode('utf-8') if data == '-1': print('can not connect to target!') continue if data == 'ag0': print('Group added!') continue if data == 'eg0': print('Entered group!') continue if data == 'eg1': print('Failed to enter group!') continue dataObj = json.loads(data) if dataObj['type'] == 'cg': #群組消息的格式定義 print('{}(from {})-> : {}'.format(dataObj['froms'], dataObj['to'], dataObj['msg'])) else: #個人消息的格式定義 print('{} ->{} : {}'.format(dataObj['froms'], userAccount, dataObj['msg'])) def main(): try: tcpCliSock.connect(ADDR) print('Connected with server') while True: loginorReg = input('(l)ogin or (r)egister a new account: ') if loginorReg in 'lL': log = login() if log: break if loginorReg in 'rR': reg = register() if reg: break myinputd = inputdata() mygetdata = getdata() myinputd.start() mygetdata.start() myinputd.join() mygetdata.join() except Exception: print('error') tcpCliSock.close() sys.exit() if __name__ == '__main__': main()
服務(wù)端
#coding:utf-8 ''' file:server.py date:2017/9/11 14:43 author:lockey email:lockey@123.com platform:win7.x86_64 pycharm python3 desc:p2p communication serverside ''' import socketserver,json,time import subprocess connLst = [] groupLst = [] ## 代號 地址和端口 連接對象 #optype = {'ag':'group adding','cp':'chat with individual','cg':'chat with group'} class Connector(object): ##連接對象類 def __init__(self,account,password,addrPort,conObj): self.account = account self.password = password self.addrPort = addrPort self.conObj = conObj class Group(object):#群組類 def __init__(self,groupname,groupOwner): self.groupId = 'group'+str(len(groupLst)+1) self.groupName = 'group'+groupname self.groupOwner = groupOwner self.createTime = time.time() self.members=[groupOwner] class MyServer(socketserver.BaseRequestHandler): def handle(self): print("got connection from",self.client_address) userIn = False global connLst global groupLst while not userIn: conn = self.request data = conn.recv(1024) if not data: continue dataobj = json.loads(data.decode('utf-8')) #如果連接客戶端發(fā)送過來的信息格式是一個列表且注冊標(biāo)識為False時進行用戶注冊或者登陸 ret = '0' if type(dataobj) == list and not userIn: account = dataobj[0] password = dataobj[1] optype = dataobj[2] existuser = False if len(connLst) > 0: for obj in connLst: if obj.account == account: existuser = True if obj.password == password: userIn = True print('{} has logged in system({})'.format(account,self.client_address)) break if optype == 'login' and (not userIn or not existuser): ret = '1' print('{} failed to logged in system({})'.format(account, self.client_address)) else: if existuser: ret = '1' print('{} failed to register({}),account existed!'.format(account, self.client_address)) else: try: conObj = Connector(account,password,self.client_address,self.request) connLst.append(conObj) print('{} has registered to system({})'.format(account,self.client_address)) userIn = True except: print('%s failed to register for exception!'%account) ret = '99' conn.sendall(ret.encode('utf-8')) if ret == '0': break while True: #除登陸注冊之外的請求的監(jiān)聽 conn = self.request data = conn.recv(1024) if not data: continue print(data) dataobj = data.decode('utf-8') dataobj = json.loads(dataobj) if dataobj['type'] == 'ag' and userIn: #如果判斷用戶操作請求類型為添加群組則進行以下操作 groupName = dataobj['groupName'] groupObj = Group(groupName,self.request) groupLst.append(groupObj) conn.sendall('ag0'.encode('utf-8')) print('%s added'%groupName) continue if dataobj['type'] == 'eg' and userIn: #入群操作 groupName = dataobj['groupName'] ret = 'eg1' for group in groupLst: if groupName == group.groupName: group.members.append(self.request) print('{} added into {}'.format(self.client_address,groupName)) ret = 'eg0' break conn.sendall(ret.encode('utf-8')) continue #客戶端將數(shù)據(jù)發(fā)給服務(wù)器端然后由服務(wù)器轉(zhuǎn)發(fā)給目標(biāo)客戶端 print('connLst',connLst) print('grouplst',groupLst) if len(connLst) > 1: sendok = False if dataobj['type'] == 'cg': #群內(nèi)廣播(除發(fā)消息的人) print('group',data) for obj in groupLst: if obj.groupName == dataobj['to']: for user in obj.members: if user != self.request: user.sendall(data) else: #個人信息發(fā)送 for obj in connLst: if dataobj['to'] == obj.account: obj.conObj.sendall(data) sendok = True if sendok == False: print('no target valid!') else: conn.sendall('-1'.encode('utf-8')) continue if __name__ == '__main__': server = socketserver.ThreadingTCPServer(('192.168.1.7',8022),MyServer) print('waiting for connection...') server.serve_forever()
運行結(jié)果示例
服務(wù)端(記錄著各客戶端的操作):
客戶端1:
有注冊、建群、群聊、點對點聊天
客戶端2:
客戶端3:
要拷貝代碼運行的話請注意平臺(win7.x86_64)和python版本號(python3.5)?。?!
相關(guān)文章
python?os.stat()如何獲取相關(guān)文件的系統(tǒng)狀態(tài)信息
這篇文章主要介紹了python?os.stat()如何獲取相關(guān)文件的系統(tǒng)狀態(tài)信息,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-11-11python使用Flask操作mysql實現(xiàn)登錄功能
這篇文章主要介紹了python使用Flask操作mysql實現(xiàn)登錄功能,代碼簡單易懂,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2018-05-05解決pymysql cursor.fetchall() 獲取不到數(shù)據(jù)的問題
這篇文章主要介紹了解決pymysql cursor.fetchall() 獲取不到數(shù)據(jù)的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-05-05使用Python-OpenCV消除圖像中孤立的小區(qū)域操作
這篇文章主要介紹了使用Python-OpenCV消除圖像中孤立的小區(qū)域操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07Python+wxPython實現(xiàn)個人鏈接收藏夾
這篇文章主要介紹了如何使用wxPython和XML數(shù)據(jù)源創(chuàng)建一個具有按鈕和Web視圖的應(yīng)用程序窗口,以便輕松管理和訪問各種網(wǎng)頁鏈接,感興趣的可以了解下2023-08-08python實現(xiàn)selenium網(wǎng)絡(luò)爬蟲的方法小結(jié)
這篇文章主要介紹了python實現(xiàn)selenium網(wǎng)絡(luò)爬蟲的方法小結(jié),本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-03-03Django中更改默認數(shù)據(jù)庫為mysql的方法示例
這篇文章主要介紹了Django中更改默認數(shù)據(jù)庫為mysql的方法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-12-12