自己写的聊天室项目

作业:(服务端,客户端)
写一个聊天室
功能:类似qq群聊
1.进入聊天室需要输入姓名,提示一下姓名不能重复

2.有人进入聊天室会向其他人发送通知
xxx 进入了聊天室
3.一个人发消息,其他人会收到消息,自己不收到
xxx 说:xxxxxxxxxxx
4.某人退出聊天室,其他人也会收到通知
xxx 退出了聊天室
5.管理员喊话功能(从服务端发送消息,所有客户端都能接收到)
管理员说:xxxxxx

功能模型:转发
需要的技术:套接字通信 udp套接字
用户存储:字典或列表
消息收发的随意性:多进程(fork)

代码设计:
1.封装 将每个功能封装为函数
2.接口测试(每实现一步测试一步)

代码的编写流程
1.搭建网络连接
2.创建多进程
3.每个进程功能编写
4.项目功能模块实现

进入聊天室???????
客户端:输入姓名,将信息发给服务端(L name)标志位
等待服务端回复 根据回复判断是否登录成功

服务端:接受请求信息 判断请求类型 判断用户名是否存在
如果存在回复不能登录,如果不 存在回复可以登录并插入到数据结构
发送通知给其他用户

def fun(l):
l.append(6)
#传递可变类型参数到函数中,打印原来的形参,同样改变了
#对可变类型的修改会影响到原来的实参
#传递一个不可变类型参数,对参数的修改不会影响原参数
l=[1,2,3,4,5]
fun(l)
print(l)


def fun(l):
l=‘world’
#传递不可变类型参数到函数中,打印原来的形参,没有改变
l=“hello”
fun(l)

print(l)

聊天
客户端:创建父子进程 发送聊天请求/接收聊天信息
服务端:接收请求信息 将消息转发给其他客户端

退出

管理员消息

代码:服务端
#!/usr/bin/env python3
#coding=utf-8

#文档说明,作者,联系方式,
‘’’
name=Yxp
email:yangxiaoping7@163.com
date:2018-9
class:AID
introduce:Chatroom server
env:python3.5
‘’’
from socket import *
import os, sys

def do_login(s,user,name,addr):
if (name in user) or name==‘管理员’:
s.sendto(‘该用户已存在’.encode(),addr)
return
s.sendto(b’OK’,addr)

#通知其他人
msg='\n欢迎%s进入聊天室'%name
for i in user:
    s.sendto(msg.encode(),user[i])
#插入用户,user是可变类型,因此可以直接修改
user[name]=addr

def do_chat(s,user,name,text):
msg ="\n%s说:%s"%(name,text)
for i in user:
if i!=name:
s.sendto(msg.encode(),user[i])

#退出聊天室
def do_quit(s,user,name):
msg=’\n’+name+‘退出聊天室’
for i in user:
if i == name:
s.sendto(b’EXIT’,user[i])
else:
s.sendto(msg.encode(),user[i])
#从字典中删除用户
del user[name]

#接受客户端请求
def do_parent(s):
#存储结构{‘zhangssan’?‘127.0.0.1’,9999)}
user={}

while True:
    msg,addr = s.recvfrom(1024)
    msgList = msg.decode().split(' ')

    #区分请求类型
    if msgList[0]=='L':
        fanhui=do_login(s,user,msgList[1],addr)
    elif msgList[0]=='C':
        do_chat(s,user,msgList[1],' '.join(msgList[2:]))    
    elif msgList[0]=='Q':
        do_quit(s,user,msgList[1])

#做管理员喊话
def do_child(s,addr):
while True:
msg=input(‘管理员消息:’)
msg='C 管理员 '+msg#发给自己
s.sendto(msg.encode(),addr)

#创建网络,创建进程,调用功能函数
def main():
#server address
ADDR=(‘0.0.0.0’,8888)

#创建套接字
s=socket(AF_INET,SOCK_DGRAM)
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
s.bind(ADDR)

#创建一个单独的进程处理管理员的喊话功能
pid=os.fork()
if pid<0:
    sys.exit('创建进程失败')
elif pid==0:
    do_child(s,ADDR)
else:
    do_parent(s)

if name==‘main’:
main()
客户端
#client.py
from socket import *
import sys,os

#发送消息
def send_msg(s,name,addr):
while True:
text=input(‘发言:’)
#如果输入quit表示退出
if text.strip()==‘quit’:
msg = 'Q ’ + name
s.sendto(msg.encode(),addr)
#整个进程都结束了
sys.exit(‘退出聊天室’)

    msg='C %s %s'%(name,text)
    s.sendto(msg.encode(),addr)

#接收消息
def recv_msg(s):
while True:
data,addr=s.recvfrom(2048)
if data.decode()==‘EXIT’:
sys.exit(0)

    print(data.decode()+"\n发言:",end='')

#创建套接字,然后登录,创建子进程
def main():
if len(sys.argv)❤️:
print(‘argv is 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:
    sys.exit('创建子进程失败')
elif pid==0:
    #不让服务端遍历姓名
    send_msg(s,name,ADDR)
else:
    recv_msg(s)

if name==‘main’:
main()

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值