Python之套接字编程

套接字:程序在网络间进行数据传输的一种技术手段,Python使用socket模块。

  • 流式套接字(SOCK_STREAM):采用TCP协议,以字节流方式实现数据传输(面向连接、可靠)
  • 数据报套接字(SOCK_DGRAM):采用UDP协议,以数据报形式实现数据传输(面向无连接、不可靠)

socket模块相关细节参见https://docs.python.org/zh-cn/3/library/socket.html

一、流式套接字:TCP传输

1.将实现通信的两台主机,分别用server端和client端表示,且只有相同类型的套接字才能进行通信
2.为防止server端和client端都阻塞,recv和send要配合

TCP通信模型

1.server端

①.创建套接字

sockfd = socket.socket(family=AF_INET, type=SOCK_STREAM,proto=0, fileno=None)
参数:family 网络地址类型 
              AF_INET默认表示ipv4;
              AF_INET6表示ipv6;
              AF_UNIX只用于单一的Unix系统进程间通信
     type 套接字类型 
              SOCK_STREAM 流式,用于TCP传输;
              SOCK_DGRAM 数据报,用于UDP传输;
              SOCK_RAW 原始套接字(可以处理普通的套接字无法处理的ICMP、IGMP等报文)
                       可以提供可靠的UDP传输,保证数据交付但不保证顺序
     proto 默认为0,表示系统会根据地址格式和套接字类别,自动选择一个合适的协议
返回值:套接字对象

②.绑定本机网络地址

sockfd.bind(address)
参数:address的格式取决于地址簇,默认AF_INET对应二元元组(ip, port)

③.设置监听——将套接字设置为监听套接字,确定监听队列大小

sockfd.listen([backlog])
参数:backlog是监听队列的大小,为0表示默认的合理值,最低为0。它指定系统accept的连接数,超过后将拒绝新连接。python3.5及以后版本为可选参数。

④.接受一个连接——等待处理客户端连接请求

connfd, addr = sockfd.accept()
返回值:返回二元元组(connfd, addr)
       connfd  新的套接字对象,用于连接客户端收发数据
       addr  连接的客户端地址

⑤.消息收发

1)接收(套接字)消息,来自client端
data = connfd.recv(bufsize)
参数:bufsize指定一次接收的最大数据量
返回值:返回一个字节对象,表示接收到的数据
2)发送消息(给套接字),好让client端接收
n = connfd.send(bytes)
    参数:bytes格式的数据
    返回值:返回已发送的字节数
connfd.sendall(bytes)
    与send()方法不同,本方法持续从bytes发送数据,直到所有数据都已发送或发生错误为止;
    send成功会返回None,出错抛异常,并不能统计发送多少数据

⑥.关闭套接字

sockfd.close()

2.client端

①.创建套接字

sockfd = socket.socket(family=AF_INET, type=SOCK_STREAM,proto=0, fileno=None)

②.请求连接服务器

sockfd.connect(address)
参数:address的格式取决于地址簇,默认AF_INET对应二元元组(ip, port)

③.收发消息

1)发送消息(给套接字),好让server端接收
n = connfd.send(bytes)
参数:bytes格式的数据
返回值:返回已发送的字节数
2)接收(套接字)消息,来自server端
data = connfd.recv(bufsize)
参数:bufsize指定一次接收的最大数据量
返回值:返回一个字节对象,表示接收到的数据

④.关闭套接字

sockfd.close()

3.TCP网络收发缓冲区

作用:用于协调数据的收发速度(这里的速度并不指代网速,而是一次接收或发送的字节数量)
说明:send和recv实际是向缓冲区发送接收数据,当缓冲区不为空时,recv就不会阻塞
TCP粘包

1. 概念:多个数据包被一次接收,前后相接,像是被“粘”在一起(没有明显的消息边界)的现象
2. 原因:
    1. 接发数据的时机没有配合好(受server端和client端程序执行时间的影响)
    2. TCP以字节流方式传输数据,且默认使用Nagle算法(尽量减少网络中的报文段数量)
3. 解决方法:
    1. 手动添加消息边界
    2. 在程序的适当位置设置一定的睡眠时间

二、数据报套接字:udp传输

UDP通信模型

1.server端

①.创建数据报套接字

sockfd = socket.socket(family=AF_INET, type=SOCK_DGRAM, proto=0, fileno=None)

②.绑定本机网络地址

sockfd.bind(address)

③.消息收发

1)接收(套接字)消息
data, address = sockfd.recvfrom(bufsize)
参数:bufsize指定一次接收的最大数据量
返回值:返回元组(bytes, address),其中bytes时字节对象,表示接收数据,address是发送端套接字地址
2)发送消息(给套接字)
n = sockfd.sendto(data, address)
参数:data是bytes格式的发送数据
     address是目标地址
返回值:返回已发送的字节数

④.关闭套接字

sockfd.close()

2.client端

①.创建数据报套接字

sockfd = socket.socket(family=AF_INET, type=SOCK_DGRAM)

②.收发消息

1)发送消息(给套接字)
n = sockfd.sendto(data, address)
参数:data是bytes格式的发送数据
     address是目标地址
返回值:返回已发送的字节数
2)接收(套接字)消息
data, address = sockfd.recvfrom(bufsize)
参数:bufsize指定一次接收的最大数据量
返回值:返回元组(bytes, address),其中bytes时字节对象,表示接收数据,address是发送端套接字地址

③.关闭套接字

sockfd.close()

三、部分socket模块函数

更多方法请参见socket函数:docs.python.org/zh-cn/3/library/socket.html

import socket
socket.gethostname()                           # 获取主机名
socket.gethostbyname('www.jd.com')             # 获取主机ip地址
socket.getservbyname('mysql')			       # 获取服务端口号
socket.getservport(3306) 					   # 获取端口对应服务
socket.inet_aton('192.168.1.1')				   # 将IP地址转换为bytes子串
socket.inet_ntoa(b'\xc0\xa8\x01\x01')		   # 将bytes子串转换为IP地址

四、套接字对象属性/函数

from socket import *

sockfd = socket(AF_INET, SOCK_STREAM)
sockfd.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)   # 设置套接字端口立即重用
sockfd.bind(('0.0.0.0', 8888))
sockfd.listen(3)
connfd, addr = sockfd.accept()
print("Connect:", addr)
connfd.recv(1024)

sockfd.type                                      # 套接字类型
sockfd.family                                    # 套接字地址类型
sockfd.getsockname()                             # 获取套接字绑定地址
sockfd.fileno()                                  # 获取套接字的文件描述符
sockfd.getpeername()                             # 获取连接套接字客户端的地址
sockfd.setsockopt(level, optname, value)         # 设置套接字选项
   参数:level 选项类别 
            SOL_SOCKET 基本套接口
            IPPROTO_IP IPv4套接口
            IPPROTO_IPV6 IPv6套接口
            IPPROTO_TCP TCP套接口
        optname 选项名称
            SOL_SOCKET
        value 选项值
sockfd.getsockopt(level, optname)                # 获取套接字选项值

level级别为SOL_SOCKET时,对应的选项及其含义

选项含义
SO_BROADCAST允许广播地址发送和接收数据包,只对UDP有效
SO_REUSEADDR当socket关闭后,允许立刻重用本地地址和端口
SO_BINDTODEVICE可以使socket只在某个特殊的网络接口(网卡)有效
SO_DONTROUTE禁止通过路由器和网关往外发送数据包,主要为了安全而用在以太网上UDP通信的一种方法
不管目的地是何IP地址,都可以防止数据离开本地网络
SO_KEEPALIVE可以使TCP通信的数据包保持连续性。这些数据包可以在没有数据传输的时候,使得通信的双方确定连接是保持的
SO_LINGER延迟关闭连接
SO_OOBINLINE可以把收到的不正常数据看成是正常的数据,也就是说会通过一个标准的对recv()的调用来接收这些数据
SO_TYPE获取套接字类型
SO_ERROR获取套接字错误
SO_DEBUG允许调试
  • 6
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值