45网络编程_UDP-创新互联

创新互联公司专注为客户提供全方位的互联网综合服务,包含不限于成都做网站、网站制作、成都外贸网站建设、浮山网络推广、小程序开发、浮山网络营销、浮山企业策划、浮山品牌公关、搜索引擎seo、人物专访、企业宣传片、企业代运营等,从售前售中售后,我们都将竭诚为您服务,您的肯定,是我们大的嘉奖;创新互联公司为所有大学生创业者提供浮山建站搭建服务,24小时服务热线:18982081108,官方网址:www.cdcxhl.com

UDP编程:

>netstat -anp tcp | find "9998"   #win下

#echo "123abc" | nc -u 127.0.0.1 9998

应用:

无连接协议,基于如下假设:网络足够好、消息不会丢包、包不会乱序;

1、音频、视频传输,一般丢些包,问题不大,最多丢些图像、听不清说话,再次说话即可;

2、海量采集数据,如传感器发来的数据,丢几十、几百条数据也没关系;

3、DNS协议,数据内容小,一个包就能查询到结果,不存在乱序、丢包,重新请求解析;

注:

即使在LAN,也不能保证不丢包,且包的到达不一定有序;

一般来说,UDP性能优于TCP,但可靠性要求高的场合还是选择用TCP;

QUIC,quick udp internet connection,google,是谷歌制定的一种基于UDP的低时延的互联网传输层协议。在2016年11月国际互联网工程任务组(IETF)召开了第一次QUIC工作组会议,受到了业界的广泛关注。这也意味着QUIC开始了它的标准化过程,成为新一代传输层协议;

UDP服务端编程步骤:

创建socket对象,sock=socket.socket(type=socket.SOCK_DGRAM);

绑定ip和port,bind()方法;

传输数据:

recvfrom(bufsize[,flags]),接收数据,获取一个二元组(string,address);

sendto(string,address),发送数据,发送某信息给某地址;

释放资源;

例:

import socket

sock = socket.socket(type=socket.SOCK_DGRAM)

addr = ('127.0.0.1', 9998)

sock.bind(addr)

data, clientaddr = sock.recvfrom(1024)

print(clientaddr)

msg = 'ack: {}'.format(data.decode())

sock.sendto(msg.encode(), clientaddr)

输出:

('127.0.0.1', 9999)

45网络编程_UDP

45网络编程_UDP

例,ChatServerUdp:

ver1:

class ChatServerUdp:

def __init__(self, ip='127.0.0.1', port=9998):

self.sock = socket.socket(type=socket.SOCK_DGRAM)

self.addr = (ip, port)

self.event = threading.Event()

self.clients = set()   #集合,去重,client主动退出后要清此数据结构

def start(self):

self.sock.bind(self.addr)

threading.Thread(target=self._recv, name='recv').start()

def stop(self):

for c in self.clients:   #业务中udp的server关闭时不会通知client

self.sock.sendto(b'end', c)

self.sock.close()   #udp的socket关闭很快,不会有很多垃圾

self.event.set()

def _recv(self):   #_recv中使用多线程场景,在一对多情况下,server发送消息和接收消息出现不匹配时,用另一线程单独处理发送数据,否则接收和发送是同步,只有等发送完才能继续再次接收

while not self.event.is_set():

data, client = self.sock.recvfrom(1024)

data = data.strip().decode()

if data == 'quit':

self.clients.remove(client)

continue   #关键,接收下个client的消息

self.clients.add(client)

print(self.clients)

msg = 'ack: {}'.format(data)

for c in self.clients:

self.sock.sendto(msg.encode(), c)

if __name__ == '__main__':

cs = ChatServerUdp()

cs.start()

myutils.show_threads()

例:

ver2:

增加ack和heartbeat机制;

心跳即一端定时发往另一端信息,一般每次发的数据越少越好,心跳时间间隔约定好就行,ack响应,一端收到另一端的消息后返回的信息;

心跳包设计:

c主动,一般由client发hb-->server,server并不需要发ack-->client,只需要记录client还活着就行;

s主动,server发hb扫一遍client,一般需要client发ack响应来表示活着,server没收到ack就断开与client连接,server移除其信息,这种实现较为复杂,用的少;

c-s双向,用的更少;

class ChatServerUdp:

def __init__(self, ip='127.0.0.1', port=9998, interval=10):

self.sock = socket.socket(type=socket.SOCK_DGRAM)

self.addr = (ip, port)

self.event = threading.Event()

self.clients = {}

self.interval = interval

def start(self):

self.sock.bind(self.addr)

threading.Thread(target=self._recv, name='recv').start()

def stop(self):

for c in self.clients:

self.sock.sendto(b'end', c)

self.sock.close()

self.event.set()

def _recv(self):

while not self.event.is_set():

lostset = set()

data, client = self.sock.recvfrom(1024)

data = data.strip().decode()

current = datetime.datetime.now().timestamp()

if data == '^hb^' or data == 'reg':

print('hb')

self.clients[client] = current

continue

elif data == 'quit':

self.clients.pop(client, None)

logging.info('{} leaving'.format(client))

         continue

self.clients[client] = current

print(self.clients)

msg = 'ack: {} {}\n{}\n'.format(*client, data)

logging.info(msg)

for c, stamp in self.clients.items():

if current - stamp > self.interval:

lostset.add(c)

else:

self.sock.sendto(msg.encode(), c)

for c in lostset:

self.clients.pop(c)

if __name__ == '__main__':

cs = ChatServerUdp()

cs.start()

myutils.show_threads()

UDP客户端编程步骤:

创建socket对象,socket.socket(type=socket.SOCK_DGRAM);

发送数据:sendto(string,address),发送某信息给某地址;

释放资源;

udp客户端编程中,只能在sendto()后,才能recvfrom(),否则OSError;

例:

sock = socket.socket(type=socket.SOCK_DGRAM)

addr = ('127.0.0.1', 9998)

data = 'test_data'.encode()

sock.sendto(data, addr)   #方式1,使用sendto()和recvfrom(),建议用此种方式

data, saddr = sock.recvfrom(1024)   #也可用recv(),只不过不知道谁发的消息了

print(data, saddr)

sock.close()

# sock.connect(addr)   #方式2,用connect()连接后才能用send()或sendto(),没有connect()连接只能用sendto();此方式可能会有问题,client-->server正常,server-->client,server上连client的端口不对了

# sock.send(data)

# data, saddr = sock.recvfrom(1024)

# print(data, saddr)

# sock.close()

例:

addr = ('127.0.0.1', 9998)

event = threading.Event()

def recv1(sock:socket.socket, event:threading.Event):

while not event.is_set():

data, saddr = sock.recvfrom(1024)

logging.info('recv: {} ; from: {}'.format(data, saddr))

sock1 = socket.socket(type=socket.SOCK_DGRAM)

sock1.sendto('udp client1 send'.encode(), addr)

threading.Thread(target=recv1, args=(sock1, event)).start()   #recvfrom()必须在sendto()或connect()之后,否则OSError,即recvfrom()操作之前应该先sendto()或connect();如果用connect(),则远端必须有服务

def recv2(sock:socket.socket, event:threading.Event):

while not event.is_set():

data, saddr2 = sock.recvfrom(1024)

logging.info('recv: {} ; from: {}'.format(data, saddr2))

sock2 = socket.socket(type=socket.SOCK_DGRAM)

sock2.connect(addr)

threading.Thread(target=recv2, args=(sock2, event)).start()

threading.Event().wait(5)

sock2.sendto('udp client2 send'.encode(), addr)

event.wait(2)

sock2.send('udp client2.1 send'.encode())

while True:

if input('>>> ').strip() == 'quit':

sock1.close()

sock2.close()

event.wait(3)

break

logging.info('end')

例,ChatClientUdp:

注:此代码有问题,在发送hb后一直阻塞

class ChatClientUdp:

def __init__(self, ip='127.0.0.1', port=9998, interval=5):

self.sock = socket.socket(type=socket.SOCK_DGRAM)

self.addr = (ip, port)

self.event = threading.Event()

self.interval = interval

self.sock.connect(self.addr)

self._sendhb()

def start(self):

# self.sock.send(b'reg')

threading.Thread(target=self._sendhb, name='hb', daemon=True).start()

# threading.Thread(target=self._recv, name='recv').start()

# self._recv()

def stop(self):

self.send()

self.sock.close()

self.event.wait(2)

self.event.set()

def _sendhb(self):

while not self.event.wait(5):

self.sock.sendto(b'^hb^', self.addr)

def send(self, msg:str='quit'):

self.sock.sendto(msg.encode(), self.addr)

def _recv(self):

while not self.event.is_set():

data, addr = self.sock.recvfrom(1024)

logging.info('recv {} from {}'.format(data, addr))

cc = ChatClientUdp()

cc.start()

while True:

data = input('plz input string>>> ')

if data == 'quit':

cc.stop()

break

else:

cc.send(data)

logging.info('end')

另外有需要云服务器可以了解下创新互联cdcxhl.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。

分享文章:45网络编程_UDP-创新互联
转载注明:https://www.cdcxhl.com/article36/dejspg.html

成都网站建设公司_创新互联,为您提供云服务器网站排名做网站网站制作营销型网站建设外贸建站

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联

绵阳服务器托管