话不多说,直接上代码.
服务器端:
server.py
from socket import *
import os,sys
\’\’\’
聊天室文件
服务端
by:dyh
\’\’\’
###用户退出并且告知所有的用户###
def do_logout(s,user,name):
#删除列表中的用户
del user[name]
msg=\’\\n\’+name+\’离开了聊天室\’
for i in user:
s.sendto(msg.encode(),addr)
return
###用户登陆代码###
def do_login(s,user,name,addr):
#用户注册时对用户name进行检查
if (name in user) or name==\’管理员\’:
s.sendto(\’该用户已存在\’.encode(),addr)
return
#用户name符合要求时发送OK给客户端提示其可以正常登陆
#用户接收到信息以后对信息判断进行登陆操作
s.sendto(b\’OK\’,addr)
msg=\’\\n欢迎%s进入聊天室\’%name
#通知所有人
for i in user:
s.sendto(msg.encode(),user[i])
#将用户插进字典
user[name]=addr
return
def do_chat(s,user,cmd):
msg=\’\\n%-4s:%s\’%(cmd[1],\’ \’.join(cmd[2:]))
#将用户name发送给除了自己之外的所有人
for i in user:
if i!=cmd[1]:
s.sendto(msg.encode(),user[i])
return
#处理客户端请求
def do_child(s):
#字典存储用户信息
user={}
#循环接收请求
while True:
msg,addr=s.recvfrom(1024)
msg=msg.decode()
cmd=msg.split(\’.\’)
#根据不同请求做不同的事情
if cmd[0]==\’l\’:
do_login(s,user,cmd[1],addr)
s.sendto(b\’OK\’,addr)
elif cmd[0]==\’m\’:
do_chat(s,user,cmd)
elif cmd[0]==\’q\’:
do_logout()
else:
s.sendto(\’请求错误\’.encode(),addr)
#发送管理员消息
def do_parent(s,ADDR):
while True:
msg=input(\’管理员发消息:\’)
msg=\’m.管理员\’+msg
s.sendto(msg.encode(),ADDR)
s.close()
sys.exit(0)
def main():
if len(sys.argv)<3:
print(\’argv error,\’)
return
HOST=sys.argv[1]
PORT=int(sys.argv[2])
ADDR=(HOST,PORT)
#使用数据b报套接字
s=socket(AF_INET,SOCK_DGRAM)
#设置端口重用代码
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
s.bind(ADDR)
###设置二级进程是为了将收消息和发消息分离###
#创建一级子进程
pid1=os.fork()
if pid1<0:
print()
elif pid1==0:
print(\’child process\’)
pid2=os.fork()
if pid2<0:
print(\”\”)
elif pid2==0:
do_child(s)
else:
#一级子进程退出,使二级子进程成为孤儿
os._exit(0)
else:
#等待一级子进程的退出
os.wait()
do_parent(s,ADDR)
if __name__==\’__main__\’:
main()
客户端:
client.py
from socket import *
import os,sys,signal
\’\’\’
聊天室文件
客户端
by:dyh
\’\’\’
#发送消息
def do_child(s,name,addr):
while True:
text=input(\”say:\”)
if text==\’quit\’:
msg=\”q.\”+name
s.sendto(msg.encode(),addr)
#从子进程种杀掉父进程
os.kill(os.getppid(),signal.SIGKILL)
sys.exit(\’已退出!\’)
else:
msg=\’m.\’+\’%s.%s\’%(name,text)
s.sendto(msg.encode(),addr)
#收消息
def do_parent(s):
while True:
msg,addr=s.recvfrom(1024)
msg=msg.decode()
msg=msg[:-1]
print(msg+\”\\nsay:\”,end=\’\’)
def main():
if len(sys.argv)<3:
print(\’argv error,\’)
return
HOST=sys.argv[1]
PORT=int(sys.argv[2])
ADDR=(HOST,PORT)
#使用数据报套接字
s=socket(AF_INET,SOCK_DGRAM)
####登陆###
while True:
name=input(\”请输入姓名:\”)
msg=\’l.\’+name
s.sendto(msg.encode(),ADDR)
data,addr=s.recvfrom(1024)
if data.decode()==\’OK\’:
print(\’###进入聊天室###\’)
break
else:
print(data.decode())
###注意这里不要设置二级进程###
#如果设置可能会在关闭客户端的时候杀死系统进程导致关机
pid=os.fork()
if pid<0:
print(\’ \’)
elif pid==0:
do_child(s,name,ADDR)
else:
#等待一级子进程的退出
do_parent(s)
if __name__==\’__main__\’:
main()