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 的绑定 ...
随机推荐
- ES6-Generator使用与改写
用Generator封装Symbol中的iterator方法: 注意:Generator的function后必须写* config:分别有3个txt文件,两个文件写路径,一个文件写要输出的内容 前置写 ...
- 【转】Web实现前后端分离,前后端解耦
一.前言 ”前后端分离“已经成为互联网项目开发的业界标杆,通过Tomcat+Ngnix(也可以中间有个Node.js),有效地进行解耦.并且前后端分离会为以后的大型分布式架构.弹性计算架构.微服务架构 ...
- [Gamma]Scrum Meeting#6
github 本次会议项目由PM召开,时间为6月1日晚上10点30分 时长10分钟 任务表格 人员 昨日工作 下一步工作 木鬼 撰写博客,组织例会 撰写博客,组织例会 swoip 前端显示屏幕,翻译坐 ...
- 【Activiti学习之八】Spring整合Activiti
环境 JDK 1.8 MySQL 5.6 Tomcat 8 idea activiti 5.22 activiti-explorer是官方提供的一个演示项目,可以使用页面管理Activiti流程.ac ...
- 解决myeclipse2017 properties中文被Unicode编码
输入:http://propedit.sourceforge.jp/eclipse/updates/ 在线安装插件解决.
- python 统计字符串中指定字符出现次数的方法
python 统计字符串中指定字符出现次数的方法: strs = "They look good and stick good!" count_set = ['look','goo ...
- mysql 添加注释
给表添加注释: alter table m_tb100_disabledsoldier comment '残疾士兵'; 给表中的字段添加注释alter table m_tb100_disable ...
- python入门之名称空间的查找顺序
名称空间的查找顺序: 局部:局部 > 全局 > 内置 全局:全局 > 内置 # 内置再找不到就报错 # 函数内部使用的名字,在定义阶段已经规定死了,与你的调用位置无关 x = 111 ...
- Xamarin.Android DatePickerFragment 日期控件
MainActivity 代码: public class MainActivity : Activity { TextView _dateDisplay; Button _dateSelectBut ...
- 快排的java实现方式,用java代码来实现快排
1. 快排的思想 通过一趟排序将要排序的数据分割成独立的两部分,前一部分的所有数据都要小于后一部分的所有数据,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据的 ...