python

超轻量级php框架startmvc

python实现简单聊天应用 python群聊和点对点均实现

更新时间:2020-05-07 16:42:01 作者:startmvc
后续代码更新和功能添加会提交到个人github主页,有兴趣可以一起来完善!如果只是拿过去

后续代码更新和功能添加会提交到个人github主页,有兴趣可以一起来完善!

如果只是拿过去运行看结果,请注意平台相关性以及python版本号,本示例开发运行平台为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模块主要是为了数据的封装传输,re的话是做一些合法性的验证
HOST = '192.168.1.7'
PORT=8022
BUFSIZE = 1024 ##缓冲区大小 1K
ADDR = (HOST,PORT)
myre = r"^[_a-zA-Z]\w{0,}"
tcpCliSock = socket(AF_INET,SOCK_STREAM)
#创建一个socket连接
userAccount = None
#用户登录标志,也用来记录登录的用户名称
def register():
#用户注册函数
 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():
#用户登录函数
 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):
#用户输入选择然后执行不同的功能程序
 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):
#接收数据线程
 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()

服务端


#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'))
 #如果连接客户端发送过来的信息格式是一个列表且注册标识为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:
 #除登陆注册之外的请求的监听
 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

 #客户端将数据发给服务器端然后由服务器转发给目标客户端
 print('connLst',connLst)
 print('grouplst',groupLst)
 if len(connLst) > 1:
 sendok = False
 if dataobj['type'] == 'cg':
 #群内广播(除发消息的人)
 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:
 #个人信息发送
 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()

运行结果示例

服务端(记录着各客户端的操作):

这里写图片描述

客户端1:

有注册、建群、群聊、点对点聊天

这里写图片描述

客户端2:

这里写图片描述

客户端3:

这里写图片描述

要拷贝代码运行的话请注意平台(win7.x86_64)和python版本号(python3.5)!!!

python 聊天应用 点对点