原
python实现简单聊天应用(群聊和点对点均实现)
<div class="article-info-box">
<div class="article-bar-top d-flex">
<span class="time">2017年09月12日 00:45:48</span>
<div class="float-right">
<span class="read-count">阅读数:2640</span>
</div>
</div>
</div>
<article>
<div id="article_content" class="article_content clearfix csdn-tracking-statistics" data-pid="blog" data-mod="popu_307" data-dsm="post">
<div class="markdown_views">
<p>后续代码更新和功能添加会提交到<a href="https://github.com/LockeyCheng/python-p2p-chating/tree/master" rel="nofollow" target="_blank">个人github主页</a>,有兴趣可以一起来完善!</p>
如果只是拿过去运行看结果,请注意平台相关性以及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:[email protected]
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()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
服务端
#coding:utf-8
'''
file:server.py
date:2017/9/11 14:43
author:lockey
email:[email protected]
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
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
运行结果示例
服务端(记录着各客户端的操作):
客户端1:
有注册、建群、群聊、点对点聊天
客户端2:
客户端3:
要拷贝代码运行的话请注意平台(win7.x86_64)和python版本号(python3.5)!!!
<div class="article-bar-bottom">
<div class="article-copyright">
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Lockey23/article/details/77940518 </div>
<div class="tags-box artic-tag-box">
<span class="label">文章标签:</span>
<a data-track-click="{"mod":"popu_626","con":"python网络编程"}" data-track-view="{"mod":"popu_626","con":"python网络编程"}" class="tag-link" href="http://so.csdn.net/so/search/s.do?q=python网络编程&t=blog" target="_blank">python网络编程 </a><a data-track-click="{"mod":"popu_626","con":"python套接字"}" data-track-view="{"mod":"popu_626","con":"python套接字"}" class="tag-link" href="http://so.csdn.net/so/search/s.do?q=python套接字&t=blog" target="_blank">python套接字 </a><a data-track-click="{"mod":"popu_626","con":"python聊天实现"}" data-track-view="{"mod":"popu_626","con":"python聊天实现"}" class="tag-link" href="http://so.csdn.net/so/search/s.do?q=python聊天实现&t=blog" target="_blank">python聊天实现 </a><a data-track-click="{"mod":"popu_626","con":"点对点聊天"}" data-track-view="{"mod":"popu_626","con":"点对点聊天"}" class="tag-link" href="http://so.csdn.net/so/search/s.do?q=点对点聊天&t=blog" target="_blank">点对点聊天 </a>
</div>
<div class="tags-box">
<span class="label">个人分类:</span>
<a class="tag-link" href="https://blog.csdn.net/lockey23/article/category/6968236" target="_blank">python </a><a class="tag-link" href="https://blog.csdn.net/lockey23/article/category/7050514" target="_blank">网络 </a>
</div>
<div class="tags-box hot-word">
<span class="label">相关热词:</span>
<a class="tag-link" href="https://blog.csdn.net/tzshlyt/article/details/53576822" target="_blank">
python实现 </a>
</div>
</div>
<!-- !empty($pre_next_article[0]) -->
<div class="related-article related-article-prev text-truncate">
<a href="https://blog.csdn.net/lockey23/article/details/77921820">
<span>上一篇</span>python实现的简单点对点(p2p)聊天 </a>
</div>
<div class="related-article related-article-next text-truncate">
<a href="https://blog.csdn.net/lockey23/article/details/77951772">
<span>下一篇</span>nginx安装配置、Nginx支持php </a>
</div>
</div>