#coding=utf-8
import socket,threading,time,threading
ip='172.20.10.2'
# ip='169.254.187.118'
# ip='169.254.83.51'
#广播地址,表示向本局域网所有电脑发送,下面两个地址都可以
#addr='<broadcast>'
# 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')