网络编程

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

11.png

UDP套接字特点

  • 可能会出现数据丢失的情况
  • 传输过程简单,实现容易
  • 数据以数据包形式表达传输
  • 数据传输效率较高

TCP 传输方法

TCP传输特点

面向连接的传输服务

  • 传输特征:提供了可靠的数据传输,可靠性指数据传输过程中无丢失,无失序,无差错,无重复。
  • 可靠性保障机制(都是操作系统网络服务自动帮应用完成的)
  • 在通信前需要建立数据连接
  • 确认应答机制
  • 通信结束要正常断开连接

三次握手(建立连接)

  • 客户端向服务器发送消息报文请求连接
  • 服务器收到请求后,回复报文确定可以连接
  • 客户端收到回复,发送最终报文连接建立

tcp_three.png

四次挥手(断开连接)

  • 主动方发送报文请求断开连接
  • 被动方收到请求后,立即回复,表示准备断开
  • 被动方准备就绪,再次发送报文表示可以断开
  • 主动方收到确定,发送最终报文完成断开

tcp_four.png

TCP服务端

1_TCP_Server.png

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()
功能:关闭套接字

11.jpg

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客户端

1_TCP_Client.png

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()

12.png

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以字节流方式进行数据传输,在接收时不区分消息边界

13.jpg

带来的影响

  • 如果每次发送内容是一个独立的含义,需要接收端独立解析此时粘包会有影响

处理方法

  • 消息格式化处理,如人为的添加消息边界,用作消息之间的分割
  • 控制发送的速度

TCP与UDP对比

传输特征

  • TCP提供可靠的数据传输,但是UDP则不保证传输的可靠性
  • TCP传输数据处理为字节流,而UDP处理为数据包形式
  • TCP传输需要建立连接才能进行数据传,效率相对较低,UDP比较自由,无需连接,效率较高

套接字编程区别

  • 创建的套接字类型不同
  • tcp套接字会有粘包,udp套接字有消息边界不会粘包
  • tcp套接字依赖listen accept建立连接才能收发消息,udp套接字则不需要
  • tcp套接字使用send,recv收发消息,udp套接字使用sendto,recvfrom

使用场景

  • tcp更适合对准确性要求高,传输数据较大的场景
  • 文件传输:如下载电影,访问网页,上传照片
  • 邮件收发
  • 点对点数据传输:如点对点聊天,登录请求,远程访问,发红包
  • udp更适合对可靠性要求没有那么高,传输方式比较自由的场景
  • 视频流的传输: 如部分直播,视频聊天等
  • 广播:如网络广播,群发消息
  • 实时传输:如游戏画面
  • 在一个大型的项目中,可能既涉及到TCP网络又有UDP网络