Socket网络编程-UDP编程
Socket网络编程-UDP编程
作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。
一.UDP编程概述
1>.UDP服务端编程流程
创建socket对象。socket.SOCK_DGRAM 绑定IP和Port,bind()方法
传输数据
接收数据,socket.recvfrom(bufsize[, flags]),获得一个二元组(string, address)
发送数据,socket.sendto(string, address) 发给某地址某信息 释放资源
2>.UDP客户端编程流程
创建socket对象。socket.SOCK_DGRAM
发送数据,socket.sendto(string, address)发给某地址某信息
接收数据,socket.recvfrom(bufsize[, flags]),获得一个二元组(string, address) 释放资源
3>.UDP编程中常用的方法
bind方法
可以指定本地地址和端口laddr,会立即占用
connect方法
可以立即占用本地地址和端口laddr,填充远端地址和端口raddr
sendto方法
可以立即占用本地地址和端口laddr,并把数据发往指定远端。只有有了本地绑定端口,sendto就可以向任何远端发送数据
send方法
需要和connect方法配合,可以使用已经从本地端口把数据发往raddr指定的远端
recv方法
要求一定要在占用了本地端口后,返回接收的数据
recvfrom方法
要求一定要占用了本地端口后,返回接收的数据和对端地址的二元组
4>.心跳机制
增加心跳heartbeat机制或ack机制。这些机制同样可以用在TCP通信的时候。 心跳,就是一端定时发往另一端的信息,一般每次数据越少越好。心跳时间间隔约定好就行。 ack即响应,一端收到另一端的消息后返回的确认信息。 心跳机制实现策略:
1.一般来说是客户端定时发往服务端的,服务端并不需要ack回复客户端,只需要记录该客户端还活 着就行了。当然服务端也可响应客户端
2.如果是服务端定时发往客户端的,一般需要客户端ack响应来表示活着,如果没有收到某客户端的ack响应,服务端移除其信息。这种实现较为复杂,用的较少
3.也可以双向都发心跳的,用的更少
二.UDP版群聊案例
1>.UDP版群聊服务端代码
#!/usr/bin/env python
#_*_conding:utf-8_*_
#@author :yinzhengjie
#blog:http://www.cnblogs.com/yinzhengjie import socket
import threading
import datetime
import logging FORMAT = "%(asctime)s %(threadName)s %(thread)d %(message)s"
logging.basicConfig(format=FORMAT, level=logging.INFO) #在服务器端代码中使用第一种心跳机制改进
class ChatUDPServer:
def __init__(self, ip='127.0.0.1', port=6688, interval=10):
self.addr = (ip, port)
self.sock = socket.socket(type=socket.SOCK_DGRAM)
self.clients = {} # 记录客户端,改为字典
self.event = threading.Event()
self.interval = interval # 默认10秒,超时就要移除对应的客户端 def start(self):
self.sock.bind(self.addr) # 立即绑定
# 启动线程
threading.Thread(target=self.recv, name='recv').start() def recv(self):
removed = set() # 超时的
while not self.event.is_set():
data, raddr = self.sock.recvfrom(1024) # 阻塞接收数据
current = datetime.datetime.now().timestamp() # float
if data.strip() == b'^hb^': # 心跳信息
print('^^^^^^^^hb', raddr)
self.clients[raddr] = current
continue
elif data.strip() == b'quit':
#有可能发来数据的不在clients中
self.clients.pop(raddr, None)
logging.info('{} leaving'.format(raddr))
continue #有信息来就更新时间
#什么时候比较心跳时间呢? 发送信息的时候,反正要遍历一遍
self.clients[raddr] = current
msg = '{}. from {}:{}'.format(data.decode(), *raddr)
logging.info(msg)
msg = msg.encode() for c, stamp in self.clients.items():
if current - stamp > self.interval:
removed.add(c)
else:
self.sock.sendto(msg, c) # 不保证对方能够收到 for c in removed:
self.clients.pop(c)
removed.clear() def stop(self):
self.event.set()
self.clients.clear()
self.sock.close() def main():
server = ChatUDPServer()
server.start() while True:
cmd = input(">>> ")
if cmd.strip() == 'quit':
server.stop()
break
logging.info(threading.enumerate())
logging.info(server.clients) if __name__ == '__main__':
main()
2>.UDP版群聊客户端代码
#!/usr/bin/env python
#_*_conding:utf-8_*_
#@author :yinzhengjie
#blog:http://www.cnblogs.com/yinzhengjie import threading
import socket
import logging FORMAT = "%(asctime)s %(threadName)s %(thread)d %(message)s"
logging.basicConfig(format=FORMAT, level=logging.INFO) #增加定时发送心跳代码
class ChatUdpClient:
def __init__(self, rip='127.0.0.1', rport=6688):
self.sock = socket.socket(type=socket.SOCK_DGRAM)
self.raddr = (rip, rport)
self.event = threading.Event() def start(self):
self.sock.connect(self.raddr) # 占用本地地址和端口,设置远端地址和端口
threading.Thread(target=self._sendhb, name='heartbeat', daemon=True).start()
threading.Thread(target=self.recv, name='recv').start() def _sendhb(self): # 心跳
while not self.event.wait(5):
self.send('^hb^') def recv(self):
while not self.event.is_set():
data, raddr = self.sock.recvfrom(1024)
msg = '{}. from {}:{}'.format(data.decode(), *raddr)
logging.info(msg) def send(self, msg:str):
self.sock.send(msg.encode())
# self.sock.sendto(msg.encode(), self.raddr) def stop(self):
self.event.set()
self.send('quit') #通知服务端退出
self.sock.close() def main():
client1 = ChatUdpClient()
client2 = ChatUdpClient()
client1.start()
client2.start()
print(client1.sock)
print(client2.sock) while True:
cmd = input('Input your words >> ')
if cmd.strip() == 'quit':
client1.stop()
client2.stop()
break
client1.send(cmd)
client2.send(cmd) if __name__ == '__main__':
main()
三.UDP协议应用
UDP是无连接协议,它基于以下假设:
网络足够好
消息不会丢包
包不会乱序
但是,即使是在局域网,也不能保证不丢包,而且包的到达不一定有序。
应用场景:
视频、音频传输,一般来说,丢些包,问题不大,最多丢些图像、听不清话语,可以重新发话语来解 决。
海量采集数据,例如传感器发来的数据,丢几十、几百条数据也没有关系。 DNS协议,数据内容小,一个包就能查询到结果,不存在乱序,丢包,重新请求解析。
一般来说,UDP性能优于TCP,但是可靠性要求高的场合的还是要选择TCP协议。 DNS使用的就是UDP协议和TCP协议。
Socket网络编程-UDP编程的更多相关文章
- 37 - 网络编程-UDP编程
目录 1 UDP协议 2 UDP通信流程 3 UDP编程 3.1 构建服务端 3.3 常用方法 4 聊天室 5 UDP协议应用 1 UDP协议 UDP是面向无连接的协议,使用UDP协议时,不需要建立连 ...
- 五十六、linux 编程——UDP 编程模型
56.1 UDP 编程模型 56.1.1 编程模型 UDP 协议称为用户数据报文协议,可靠性比 TCP 低,但执行效率高 56.1.2 API (1)发送数据 函数参数: sockfs:套接字文件描述 ...
- socket与TCP/UDP编程~
ket接口是TCP/IP网络的API,Socket接口定义了许多函数或例程,程序员可以用它们来开发TCP/IP网络上的应用程序.要学Internet上的TCP/IP网络编程,必须理解Socket接口. ...
- python的socket编程之udp编程
在上篇文章中,仅仅讲述了如何进行了TCP编程,在本章中,将讲述使用udp进行编码,先看如下的代码,服务器端: root@python 513]# cat serverudp.py #!/usr/bin ...
- UNIX网络编程——UDP编程模型
使用UDP编写的一些常见得应用程序有:DNS(域名系统),NFS(网络文件系统)和SNMP(简单网络管理协议). 客户不与服务器建立连接,而是只管使用sendto函数给服务器发送数据报,其中必须指定目 ...
- 网络编程——UDP编程
一个简单的聊天代码:运行结果: 在这个程序之中,由于recvfrom函数拥塞函数,没有数据时会一直阻塞,所以客户端和服务器端只能通过一回一答的方式进行信息传递.严格的讲UDP没有明确的客户端和服务端, ...
- 五十五 网络编程 UDP编程
TCP是建立可靠连接,并且通信双方都可以以流的形式发送数据.相对TCP,UDP则是面向无连接的协议. 使用UDP协议时,不需要建立连接,只需要知道对方的IP地址和端口号,就可以直接发数据包.但是,能不 ...
- 五十八、linux 编程——UDP 编程 广播
58.1 广播介绍 58.1.1 介绍 广播实现一对多的通讯 它通过向广播地址发送数据报文实现的 58.1.2 套接字选项 套接字选项用于修饰套接字以及其底层通讯协议的各种行为.函数 setsocko ...
- 五十七、linux 编程——UDP 编程 域名解析
57.1 介绍 57.1.1 域名解析 57.1.2 域名解析函数 gethostent 可以获取多组,gethostbyname 只可以获取一组 /etc/hosts 文件设置了域名和 IP 的绑定 ...
随机推荐
- vue自学小demo----前端
vue学习的小demo,实现简单的页面项目的增删 代码如下 <!DOCTYPE html> <html> <head> <meta charset=" ...
- 【IntelliJ IDEA学习之八】版本控制之SVN
版本:IntelliJIDEA2018.1.4 一.SVN1.安装SVN客户端,command line client tools默认是不安装的,这里要勾选上(不用重新卸载安装,只找到安装程序,选择 ...
- SpringMvc通过controller上传文件代码示例
上传文件这个功能用的比较多,不难,但是每次写都很别扭.记录在此,以备以后copy用. package com.**.**.**.web.api; import io.swagger.annotatio ...
- 【原】无脑操作:Webstorm集成Git/Github
Webstorm作为前端开发的主流工具,对Git及Github可以非常简便的集成. 1.开发环境:(如何安装就不说了) ① Webstorm 2018 ② git version 2.20.1 ③ G ...
- c# winFrom Close报错 System.ObjectDisposedException:“无法访问已释放的对象。
System.ObjectDisposedException:“无法访问已释放的对象. ObjectDisposed_ObjectName_Name” 查了一下发现是 InitializeCompon ...
- cad快捷图标中的启动参数
!!!转载 http://blog.sina.com.cn//s/blog_6848608101017v4w.html 有时候需要判断一下是否是硬件加速.Ribbon等原因造成了软件的问题,需要在 ...
- linux --------- linux系统 安装tomcat
1.下载tomcat http://tomcat.apache.org/ 进入官网选download 点击 Archies 2.版本的下载与选择 3.使用winscp传递文件 4.查看所在位置 5 ...
- [转帖]k8s 基本使用(下)
k8s 基本使用(下) https://www.jianshu.com/p/116ce601a60f 如果你没有看过上篇的话,推荐阅读完 k8s 基本使用(上)后再阅读本篇内容. kubectl cr ...
- Linux下查看.so和可执行文件是否debug编译
如何判断一个.so是否是debug编译的? 如果用此方法:用file来查看一个.so, 根据是否包含”not stripped”来判断该.so是否是debug编译的.然而stripped/not st ...
- Feign实现自定义错误处理
关键操作 实现ErrorDecoder接口 问题和背景 最近项目中在大量使用Feign和OkHttp作为http客户端使用,开发效率得到显著的提升.但也面临一些问题,比如每个下游系统的异常返回方式不同 ...