网络编程
UDP 传输方法
套接字简介
套接字(Socket):实现网络编程进行数据传输的一种技术手段,网络上各种各样的网络服务大多都是基于 Socket 来完成通信的
- Python套接字编程模块:import socket
UDP套接字编程
sock=socket.socket(family,type)
功能:创建套接字
参数:family 网络地址类型 AF_INET表示ipv4
type 套接字类型 SOCK_DGRAM 表示udp套接字 (也叫数据报套接字)
返回值: 套接字对象
sock.bind(addr)
功能: 绑定本机网络地址
参数: 二元元组 (ip,port) ('0.0.0.0',8888)
data,addr = sock.recvfrom(buffersize)
功能: 接收UDP消息
参数: 每次最多接收多少字节
返回值: data 接收到的内容
addr 消息发送方地址
n = sock.sendto(data,addr)
功能: 发送UDP消息
参数: data 发送的内容 bytes格式
addr 目标地址
返回值:发送的字节数
sock.close()
功能:关闭套接字
UDP服务端代码示例
"""
udp示例
"""
from socket import *
#创建套接字
udpsocket = socket(AF_INET,SOCK_DGRAM)
#绑定网卡ip
udpsocket.bind(('0.0.0.0',8888))
while 1:
#接收
data,addr = udpsocket.recvfrom(1024)
print(addr,data.decode())#data->type
if data.decode() == '##':
# 回复
udpsocket.sendto('##'.encode(),addr)
# 关闭
udpsocket.close()
break
else:
udpsocket.sendto('ok'.encode(), addr)
UDP 客户端代码示例
"""
udp 客户端
"""
from socket import *
ADDR = ('127.0.0.1',8888)
udpsocket = socket(AF_INET,SOCK_DGRAM)
while 1:
udpsocket.sendto(input(">>").encode(),ADDR)
#接收
data,addr = udpsocket.recvfrom(1024)
print(addr,data.decode())#data->type
if data.decode() == '##':
udpsocket.close()
break
UDP套接字特点
- 可能会出现数据丢失的情况
- 传输过程简单,实现容易
- 数据以数据包形式表达传输
- 数据传输效率较高
TCP 传输方法
TCP传输特点
面向连接的传输服务
- 传输特征:提供了可靠的数据传输,可靠性指数据传输过程中无丢失,无失序,无差错,无重复。
- 可靠性保障机制(都是操作系统网络服务自动帮应用完成的)
- 在通信前需要建立数据连接
- 确认应答机制
- 通信结束要正常断开连接
三次握手(建立连接)
- 客户端向服务器发送消息报文请求连接
- 服务器收到请求后,回复报文确定可以连接
- 客户端收到回复,发送最终报文连接建立
四次挥手(断开连接)
- 主动方发送报文请求断开连接
- 被动方收到请求后,立即回复,表示准备断开
- 被动方准备就绪,再次发送报文表示可以断开
- 主动方收到确定,发送最终报文完成断开
TCP服务端
sock=socket.socket(family,type)
功能:创建套接字
参数:family 网络地址类型 AF_INET表示ipv4
type 套接字类型 SOCK_STREAM 表示tcp套接字 (也叫流式套接字)
返回值: 套接字对象
sock.bind(addr)
功能: 绑定本机网络地址
参数: 二元元组 (ip,port) ('0.0.0.0',8888)
sock.listen(n)
功能 : 将套接字设置为监听套接字,确定监听队列大小
参数 : 监听队列大小
conn,addr = sock.accept()
功能: 阻塞等待处理客户端请求
返回值: conn 客户端连接套接字
addr 连接的客户端地址
data = conn.recv(buffersize)
功能 : 接受客户端消息
参数 :每次最多接收消息的大小
返回值: 接收到的内容
n = conn.send(data)
功能 : 发送消息
参数 :要发送的内容 bytes格式
返回值: 发送的字节数
conn.close()
功能:关闭连接
sock.close()
功能:关闭套接字
TCP服务端代码示例
"""
tcp示例
"""
from socket import *
#创建套接字
tcpsocket = socket(AF_INET,SOCK_STREAM)
#绑定网卡ip
tcpsocket.bind(('0.0.0.0',8888))
#设置监听
tcpsocket.listen(5)
while 1:
#处理
print('waiting')
conn,addr = tcpsocket.accept()
print(addr)
while 1:
#接收
data = conn.recv(1024)
if not data or data.decode() == '##':
#关闭当前连接
conn.close()
break
else:
print(data.decode()) # data->type
conn.send(b'thanks')
break
#关闭tcp套接字
tcpsocket.close()
TCP客户端
sock=socket.socket(family,type)
功能:创建套接字
参数:family 网络地址类型 AF_INET表示ipv4
type 套接字类型 SOCK_STREAM 表示tcp套接字 (也叫流式套接字)
返回值: 套接字对象
sock.connect(server_addr)
功能:连接服务器
参数:元组 服务器地址
data = conn.recv(buffersize)
功能 : 接受客户端消息
参数 :每次最多接收消息的大小
返回值: 接收到的内容
n = conn.send(data)
功能 : 发送消息
参数 :要发送的内容 bytes格式
返回值: 发送的字节数
sock.close()
功能:关闭套接字
TCP客户端代码示例
"""
tcp客户端
"""
from socket import *
ADDR = ('127.0.0.1',8888)
tcpsocket = socket()
tcpsocket.connect(ADDR)
while 1:
str = input('>>')
tcpsocket.send(str.encode())
if str == '##':
break
data = tcpsocket.recv(1024)
print(data.decode())
tcpsocket.close()
TCP套接字细节
- tcp连接中当一端退出,另一端如果阻塞在recv,此时recv会立即返回一个空字串。
- tcp连接中如果一端已经不存在,仍然试图通过send向其发送数据则会产生BrokenPipeError
- 一个服务端可以同时连接多个客户端,也能够重复被连接
Traceback (most recent call last):
File "/home/tarena/mouth02/day11/02_tcp_server.py", line 29, in <module>
conn.send(b'thanks')
BrokenPipeError: [Errno 32] Broken pipe
tcp粘包原因
- 为了解决数据再传输过程中可能产生的速度不协调问题,操作系统设置了缓冲区
- 实际网络工作过程比较复杂,导致消息收发速度不一致
- tcp以字节流方式进行数据传输,在接收时不区分消息边界
带来的影响
- 如果每次发送内容是一个独立的含义,需要接收端独立解析此时粘包会有影响
处理方法
- 消息格式化处理,如人为的添加消息边界,用作消息之间的分割
- 控制发送的速度
TCP与UDP对比
传输特征
- TCP提供可靠的数据传输,但是UDP则不保证传输的可靠性
- TCP传输数据处理为字节流,而UDP处理为数据包形式
- TCP传输需要建立连接才能进行数据传,效率相对较低,UDP比较自由,无需连接,效率较高
套接字编程区别
- 创建的套接字类型不同
- tcp套接字会有粘包,udp套接字有消息边界不会粘包
- tcp套接字依赖listen accept建立连接才能收发消息,udp套接字则不需要
- tcp套接字使用send,recv收发消息,udp套接字使用sendto,recvfrom
使用场景
- tcp更适合对准确性要求高,传输数据较大的场景
- 文件传输:如下载电影,访问网页,上传照片
- 邮件收发
- 点对点数据传输:如点对点聊天,登录请求,远程访问,发红包
- udp更适合对可靠性要求没有那么高,传输方式比较自由的场景
- 视频流的传输: 如部分直播,视频聊天等
- 广播:如网络广播,群发消息
- 实时传输:如游戏画面
- 在一个大型的项目中,可能既涉及到TCP网络又有UDP网络
最后一次更新于2022-11-23 16:16
0 条评论