python之UDP实现局域网聊天 作者:马育民 • 2019-05-26 09:10 • 阅读:10111 ``` #coding=utf-8 import socket,threading,time,threading ip='172.20.10.2' # ip='169.254.187.118' # ip='169.254.83.51' #广播地址,表示向本局域网所有电脑发送,下面两个地址都可以 #addr='' # addr='255.255.255.255' PORT=8000 INTERVAL=1 TIMEOUT=5 # 邻居 neighbors=[] nickname='马老师' msgnum=0 msghis={} ''' 自定义协议,应用层。tcp、udp 指令:相应的内容 cmd:ok 代表接收数据成功 msg:文本消息 例子: msg:ok 软件设计文档 1. 启动程序时,广播发送上线指令,协议: cmd:online 2. 收到李雷的cmd:online指定的电脑,给李雷回复(打招呼) cmd:hello 网络协议文档 cmd:online cmd:hello msg:序号:文本 例子:msg:100:我妈说的:不让我和傻子玩 cmd:ok:序号 ''' def recv(): while True: data,addr=udp.recvfrom(1024) content=data.decode('utf-8') # print(content,addr) # ok不是普通的字符串,而是一种指令 if content[:3]=='cmd': if content[4:6]=='ok': rmsgnum=content[7:] print('%s收到消息,rmsgnum:%s'%(addr[0],rmsgnum)) msghis.pop(rmsgnum) elif content[4:10]=='online': rnickname=content[11:] # 判断接收到online指令的ip地址,如果是自己的ip,将不提示 ips=getips() if addr[0] not in ips : print('【系统提示】:%s(%s) 上线'%(rnickname,addr[0])) udp.sendto(('cmd:hello:'+nickname).encode('utf-8'),(addr[0],PORT)) addneighbors({'ip':addr[0],'nickname':rnickname}) elif content[4:9]=='hello': rnickname=content[10:] addneighbors({'ip':addr[0],'nickname':rnickname}) elif content[:3]=='msg': index=content.find(':',4) rmsgnum=content[4:index ] scontent='cmd:ok:%s'%rmsgnum udp.sendto(scontent.encode('utf-8'),(addr[0],8000)) print(content[index+1:],addr) def addneighbors(ip): # 做添加ip判断,判断是否是自己,判断是否重复添加 if ip not in neighbors: neighbors.append(ip) def getips(): ''' 获取本机所有ipv4的ip地址 ''' ips=[] hostname = socket.gethostname() addrs = socket.getaddrinfo(hostname,None,family=socket.AF_INET) for item in addrs: ips.append(item[4][0]) return ips def broadcast(ip,port,content): ''' 广播 ''' with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as udp: # 192.168.0.100 8001 # 169.254.0.100 8001 udp.bind((ip,port+1)) # print('-------',port) #下面这行代码允许发送广播数据 udp.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) data=content.encode('UTF-8') # data=b'abc' udp.sendto(data,('255.255.255.255',port)) def online(): ''' 发送上线广播 ''' for ip in getips(): broadcast(ip,PORT,'cmd:online:'+nickname) def checkmsghis(): global msghis for key in list(msghis.keys()): value=msghis[key] t=value[1] if time.time()-t > TIMEOUT: print('【提示】发送给%s的消息,对方未收到,消息:%s'%(value[2],value[0])) msghis.pop(key) threading.Timer(INTERVAL,checkmsghis).start() if __name__ == "__main__": udp=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # 一个端口既能实现收,也能实现发 # portstr=input('请输入绑定端口号(默认8000):') # port=8000 # if portstr!='': # port=int(portstr) udp.bind(('0.0.0.0',PORT)) print('-------2',PORT) print('绑定%d成功,开始接收数据...'%PORT) t=threading.Thread(target=recv) t.start() online() threading.Timer(INTERVAL,checkmsghis).start() while True: ''' to ip:port msg ,例子 to 192.168.1.100 8000 你好 ''' s=input('>') l=s.split(' ') if l[0]=='to': msgnum+=1 content=('msg:%s:%s')%(msgnum,l[2]) udp.sendto(content.encode('UTF-8'),(l[1],PORT)) msghis[str(msgnum)]=(l[2],time.time(),l[1]) elif l[0]=='sn': print('邻居列表') for item in neighbors: print(' ',item) elif l[0]=='smh': print('msghis',msghis) elif l[0]=='help': print('to ip 消息') print('sn 查看邻居') else: print('格式错误,正确格式:to ip msg') ``` 原文出处:http://malaoshi.top/show_1EF3Oo1cYAdk.html