还是用UDP,socket作为主体来实现,之前我们已经实现过单对单socket通信,这次想实现群发功能
原理其实就是一台服务器在负责分配转发数据,来达成广播的效果,这些思路其实也差不多
但是多人聊天没有这么强的规整性,你可能没等到A的消息,就要去和B说话了,多线程就可以实现这一点
给个链接,感觉写的很好:https://www.cnblogs.com/yeayee/p/4952022.html
主要就是依靠threading模块
你可以理解为,我们创建了一个类似于数组的空间,来存放我们所有要执行的工作,然后同时开始,然后通过阻塞父进程来等待子进程结束,这就是多线程工作
直接上代码段好了,用txt和字典可以伪造一个非常非常破的聊天室,自己其实感觉做的挺垃圾的,毕竟最后的成品,本地就算是存储了个人信息,要群发消息的话,还需要服务器存放的字典的values来追踪各个地址,完全是脱节的,唉,菜到落泪,不会数据库,也没有界面,不过总算是熟悉了一波字典的操作,争取早日用上json
SERVER:
import json
import socket
name_dict={} #空字典
def register(data,client_addr):
f=open("members.txt",'a+')
data=data[9::]
key=data.decode('utf-8')
line=f.readline().strip()
print(line)
result=line.find(key)
if result >=0:
s="your information has been used, please register again"
server.sendto(s.encode('utf-8'),client_addr)
f.close()
return 1
while line:
line = f.readline().strip()
result=line.find(key)
if result>=0:
s="your information has been used, please register again"
server.sendto(s.encode('utf-8'),client_addr)
f.close()
return 1
#print(key[:8:])
#print(key[9::])
f.write('name/password:%s\n' %key)
s='welcome,now you can login'
server.sendto(s.encode('utf-8'),client_addr)
f.close()
return 0
def login(data,client_addr):
f=open("members.txt",'r+')
data=data[9::]
#print(data)
key=data.decode('utf-8')
print(key)
#data,client_addr = server.recvfrom(BUFSIZE) #从缓冲区读取1024个字节,The return value is a pair (bytes, client_address)
#try:
line=f.readline().strip()
result=line.find(key)
print(result)
if result >=0:
name_dict[key]=client_addr
s='wait for you for a long time, what do you want to tell to others'
server.sendto(s.encode('utf-8'),client_addr)
f.close()
return 1
while line:
line=f.readline().strip()
result=line.find(key)
if result >=0:
name_dict[key]=client_addr
s='wait for you for a long time, what do you want to tell to others'
server.sendto(s.encode('utf-8'),client_addr)
f.close()
return 1
s='wrong password or name, goodbye' #make client closed
server.sendto(s.encode('utf-8'),client_addr)
f.close()
return 0
def qunfa111(data,client_addr):
#data=data.decode('utf-8')
data=data[9::]
flag=0
for value in name_dict.values():
if value==client_addr:
flag=1
for value in name_dict.values():
if value==client_addr:
continue
server.sendto(data,value)
if flag==0:
server.sendto(b'please login first',client_addr)
return
def sifa1111(data,client_addr,toname):
toname=data[9:28:]
print(toname)
data2=data[28::]
print(data2)
flag=0
print(name_dict)
for value in name_dict.values():
if value==client_addr:
flag=1
for key in name_dict.keys():
if key==toname:
server.sendto(data2,name_dict[toname])
server.sendto(b'OK',client_addr)
return
flag=2
if flag==2:
server.sendto(b'who is he?',client_addr)
return
if flag==0:
server.sendto(b'please login first',client_addr)
return
#-----------------------------------------------------------------------------------------------------------------------------------------------------
BUFSIZE = 1024 #规定缓冲区的大小
ip_port = ('127.0.0.1', 9999)
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # udp协议
server.bind(ip_port)
print('Listening at {}'.format(server.getsockname)) #getsockname()可以获取套接字目前绑定的IP地址即端口,返回的是一个二元组
#s='welcome, what do you want to do: QUIT,register,login'
#server.sendto(s.encode('utf-8'),client_addr)
while True:
data,client_addr = server.recvfrom(BUFSIZE) #从缓冲区读取1024个字节,The return value is a pair (bytes, client_address)
print(data[:8:])
if data[:8:]==b'Leaving~':
server.sendto(b'see you later',client_addr)
for key in name_dict.keys():
if name_dict[key]==client_addr:
del name_dict[key]
continue
elif data[:8:]==b'register':
#print(data)
n=1
while(n):
n=register(data,client_addr)
elif data[:8:]==b'logining':
#data=data[9::]
login(data,client_addr)
elif data[:8:]==b'sifa1111':
sifa1111(data,client_addr,data[9:12:]) #名字暂时只能3个字符
elif data[:8:]==b'qunfa111':
qunfa111(data,client_addr)
server.close()
CLIENT
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import socket
import threading
BUFSIZE = 1024
client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # udp协议
print('welcome, what do you want to do: Leaving~,register,logining')
ip_port = ('127.0.0.1', 9999)
def recv():
while(True):
client.connect(ip_port)
data,server_addr= client.recvfrom(BUFSIZE)
if data==b'see you later': #输入QUIT即可断开连接
print('Data recived from sever:',data,server_addr)
client.close()
print('Data recived from sever:',data.decode('gb2312','ignore'),server_addr)
def send():
while(True):
msg = input(">> ").strip() #strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列
client.sendto(msg.encode('utf-8'),ip_port) # 以utf-8编码对u进行编码,获得bytes类型对象
threads=[]
t1 = threading.Thread(target=send)
threads.append(t1)
t2 = threading.Thread(target=recv)
threads.append(t2)
for i in range(len(threads)): #启动线程
threads[i].start()
threads[0].join() #send未结束不可以停止
群发问题不大,但是私聊还有问题,调对齐很麻烦,先不弄了