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编程的更多相关文章

  1. 37 - 网络编程-UDP编程

    目录 1 UDP协议 2 UDP通信流程 3 UDP编程 3.1 构建服务端 3.3 常用方法 4 聊天室 5 UDP协议应用 1 UDP协议 UDP是面向无连接的协议,使用UDP协议时,不需要建立连 ...

  2. 五十六、linux 编程——UDP 编程模型

    56.1 UDP 编程模型 56.1.1 编程模型 UDP 协议称为用户数据报文协议,可靠性比 TCP 低,但执行效率高 56.1.2 API (1)发送数据 函数参数: sockfs:套接字文件描述 ...

  3. socket与TCP/UDP编程~

    ket接口是TCP/IP网络的API,Socket接口定义了许多函数或例程,程序员可以用它们来开发TCP/IP网络上的应用程序.要学Internet上的TCP/IP网络编程,必须理解Socket接口. ...

  4. python的socket编程之udp编程

    在上篇文章中,仅仅讲述了如何进行了TCP编程,在本章中,将讲述使用udp进行编码,先看如下的代码,服务器端: root@python 513]# cat serverudp.py #!/usr/bin ...

  5. UNIX网络编程——UDP编程模型

    使用UDP编写的一些常见得应用程序有:DNS(域名系统),NFS(网络文件系统)和SNMP(简单网络管理协议). 客户不与服务器建立连接,而是只管使用sendto函数给服务器发送数据报,其中必须指定目 ...

  6. 网络编程——UDP编程

    一个简单的聊天代码:运行结果: 在这个程序之中,由于recvfrom函数拥塞函数,没有数据时会一直阻塞,所以客户端和服务器端只能通过一回一答的方式进行信息传递.严格的讲UDP没有明确的客户端和服务端, ...

  7. 五十五 网络编程 UDP编程

    TCP是建立可靠连接,并且通信双方都可以以流的形式发送数据.相对TCP,UDP则是面向无连接的协议. 使用UDP协议时,不需要建立连接,只需要知道对方的IP地址和端口号,就可以直接发数据包.但是,能不 ...

  8. 五十八、linux 编程——UDP 编程 广播

    58.1 广播介绍 58.1.1 介绍 广播实现一对多的通讯 它通过向广播地址发送数据报文实现的 58.1.2 套接字选项 套接字选项用于修饰套接字以及其底层通讯协议的各种行为.函数 setsocko ...

  9. 五十七、linux 编程——UDP 编程 域名解析

    57.1 介绍 57.1.1 域名解析 57.1.2 域名解析函数 gethostent 可以获取多组,gethostbyname 只可以获取一组 /etc/hosts 文件设置了域名和 IP 的绑定 ...

随机推荐

  1. vue自学小demo----前端

    vue学习的小demo,实现简单的页面项目的增删 代码如下 <!DOCTYPE html> <html> <head> <meta charset=" ...

  2. 【IntelliJ IDEA学习之八】版本控制之SVN

    版本:IntelliJIDEA2018.1.4 一.SVN1.安装SVN客户端,command line client tools默认是不安装的,这里要勾选上(不用重新卸载安装,只找到安装程序,选择  ...

  3. SpringMvc通过controller上传文件代码示例

    上传文件这个功能用的比较多,不难,但是每次写都很别扭.记录在此,以备以后copy用. package com.**.**.**.web.api; import io.swagger.annotatio ...

  4. 【原】无脑操作:Webstorm集成Git/Github

    Webstorm作为前端开发的主流工具,对Git及Github可以非常简便的集成. 1.开发环境:(如何安装就不说了) ① Webstorm 2018 ② git version 2.20.1 ③ G ...

  5. c# winFrom Close报错 System.ObjectDisposedException:“无法访问已释放的对象。

    System.ObjectDisposedException:“无法访问已释放的对象. ObjectDisposed_ObjectName_Name” 查了一下发现是 InitializeCompon ...

  6. cad快捷图标中的启动参数

    !!!转载   http://blog.sina.com.cn//s/blog_6848608101017v4w.html 有时候需要判断一下是否是硬件加速.Ribbon等原因造成了软件的问题,需要在 ...

  7. linux --------- linux系统 安装tomcat

    1.下载tomcat  http://tomcat.apache.org/ 进入官网选download  点击 Archies 2.版本的下载与选择 3.使用winscp传递文件 4.查看所在位置 5 ...

  8. [转帖]k8s 基本使用(下)

    k8s 基本使用(下) https://www.jianshu.com/p/116ce601a60f 如果你没有看过上篇的话,推荐阅读完 k8s 基本使用(上)后再阅读本篇内容. kubectl cr ...

  9. Linux下查看.so和可执行文件是否debug编译

    如何判断一个.so是否是debug编译的? 如果用此方法:用file来查看一个.so, 根据是否包含”not stripped”来判断该.so是否是debug编译的.然而stripped/not st ...

  10. Feign实现自定义错误处理

    关键操作 实现ErrorDecoder接口 问题和背景 最近项目中在大量使用Feign和OkHttp作为http客户端使用,开发效率得到显著的提升.但也面临一些问题,比如每个下游系统的异常返回方式不同 ...