用Python写一个聊天室
功能 : 类似qq群聊
1. 进入聊天室需要输入姓名,姓名不能重复
2. 有人进入聊天室会向其他人发送通知
xxx 进入了聊天室
3. 一个人发消息,其他人会收到消息
xxx 说 : xxxxxxxx
4. 某人退出聊天室,其他人也会收到通知
xxx 退出了聊天室
先看我写的代码的运行结果:
准备文件:
tcp_s.py 服务端代码
tcp_c.py 用户端代码
tcp_s.py 代码:
from socket import *
from time import sleep
from select import *
import os
import sys
s = socket(AF_INET,SOCK_STREAM,0) #创建套接字对象
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #设置端口可重用
s.bind(('0.0.0.0',8888)) #绑定IP和端口号
s.listen(10) #设置最大可连接数
rlist = [s] #设置 读列表
wlist = [] #设置 写列表
xlist = [] #设置 出错列表
while True: #无限接收用户端信息
rs,ws,xs = select(rlist,wlist,xlist) #将s对象托管给select对象
for r in rs: #遍历返回的对象列表
if r is s: #如果对象是 s 套接字对象(服务端本身)
c,addr = s.accept() #与用户端连接
rlist.append(c) #将此用户对象保存起来
else:#如果对象是 c 套接字对象(用户端)
data = r.recv(1024).decode() #最大一次性接收1024字节,并将接收的内容转化为UTF8
if not data: #如果传过来没有数据,则认为是用户端已断开
rlist.remove(r) #将读列表中的此用户删除
else:#如果有数据传过来,则做相应处理
data = data.split('_:_') #拆分姓名和说话内容为一个列表
print(data) #打印列表
if data[1] == '': #如果没有传过来说话内容,则说明是第一次连接
data = data[0] + ' 进入聊天室' #生成 某某进入聊天室 的提示信息
for x in rlist: #遍历所有的 套接字对象
if x is s: #如果遍历到的套接字对象是服务端自己的对象,则略过
pass
else:#如果遍历到的套接字对象是用户端的对象,则发送消息(给所有用户发送一条 某某进入聊天室 的消息)
x.send(data.encode()) #发送消息
else: #如果有说话内容传入,则处理
data = data[0]+'说:'+data[1] #拆分说话人姓名和说话内容 保存为一个列表
for x in rlist: #遍历所有的 套接字对象
if x is s: #如果遍历到的套接字对象是服务端自己的对象,则略过
pass
else:#如果遍历到的套接字对象是用户端的对象,则发送消息(给所有用户发送一条 某某说:XXXXX 的消息)
x.send(data.encode()) #发送消息
tcp_c.py代码:
from socket import *
from time import sleep
from select import *
import os
s = socket(AF_INET,SOCK_STREAM,0) #创建套接字对象
addr = ('127.0.0.1',8888) #设置连接地址信息
name = input('请输入姓名>>') #要求输入姓名
s.connect(addr) #连接至服务端
info = name + '_:_' #设置信息的格式
s.send(info.encode()) #将名字发送至服务端
rlist = [s] #设置 读列表
wlist = [] #设置 写列表
xlist = [] #设置 出错列表
pid = os.fork() #开启一个子进程,用于专门接收从服务端传过来的对话数据
if pid == 0: #如果是子进程(用于处理服务端数据的进程)
while True: #无限接收服务端信息
rs,ws,xs = select(rlist,wlist,xlist)
e = 0 #设置一个标记 值 为0
for r in rs: #遍历所有的套接字对象
if r is s: #如果遍历到的套接字对象是 本模块的对象
data = r.recv(1024).decode() #接收从服务器传过来的数据
if not data: #如果没有数据,则说明服务端要断开
e = 1 #设置标记值为1
else:#如果有数据,则打印
print(data)#打印出数据
if e == 1: #如果标记被改为1,说明要断开,则跳出循环
break
else:#循环结束时打印一条消息
print('子结束')
elif pid > 0: #如果是当前进程(用于发送消息的进程)
while True: #无限处理要发送的信息
rs,ws,xs = select(rlist,wlist,xlist)
e = 0 #设置一个标记 值 为0
for r in rs: #遍历所有的套接字对象
if r is s: #如果遍历到的套接字对象是 本模块的对象
info = input('') #等待用户输入信息
if not info: #如果没有输入任何信息,则代表用户想要断开连接
e = 1 #设置标记值为1
info = name + '_:_退出了聊天室' #生成一条给服务端的信息
r.send(info.encode()) #最后再给服务端发送一句退出的消息
else: #如果有输入数据,则处理
info = name + '_:_' + info #将数据拼接成相应的格式
r.send(info.encode()) #将数据发送给服务端
if e == 1: #如果标记被改为1,说明要断开,则跳出循环
break
print('父结束') #循环结束时打印一条消息
else:
print('ERROR',pid)
s.close()
print('结束')
发表评论