ThankNeko's Blog ThankNeko's Blog
首页
  • 操作系统

    • Linux基础
    • Linux服务
    • WindowsServer笔记
    • Ansible笔记
    • Shell笔记
  • 容器服务

    • Docker笔记
    • Kubernetes笔记
    • Git笔记
  • 数据库服务

    • MySQL笔记
    • ELK笔记
    • Redis笔记
  • 监控服务

    • Zabbix笔记
  • Web服务

    • Nginx笔记
    • Tomcat笔记
  • 数据处理

    • Kettle笔记
  • Python笔记
  • Bootstrap笔记
  • C笔记
  • C++笔记
  • Arduino笔记
  • 分类
  • 标签
  • 归档
  • 随笔
  • 关于
GitHub (opens new window)

Hoshinozora

尽人事,听天命。
首页
  • 操作系统

    • Linux基础
    • Linux服务
    • WindowsServer笔记
    • Ansible笔记
    • Shell笔记
  • 容器服务

    • Docker笔记
    • Kubernetes笔记
    • Git笔记
  • 数据库服务

    • MySQL笔记
    • ELK笔记
    • Redis笔记
  • 监控服务

    • Zabbix笔记
  • Web服务

    • Nginx笔记
    • Tomcat笔记
  • 数据处理

    • Kettle笔记
  • Python笔记
  • Bootstrap笔记
  • C笔记
  • C++笔记
  • Arduino笔记
  • 分类
  • 标签
  • 归档
  • 随笔
  • 关于
GitHub (opens new window)
  • Python笔记

    • 基础知识

    • 并发编程

    • 爬虫笔记

    • 模块笔记

      • PyInstaller
      • Jieba
      • Kubernetes
      • Logging
      • Loguru
      • Socket
        • 介绍
        • Socket家族
          • AF_INET
          • AF_UNIX
        • Socket类型
          • SOCK_STREAM
          • SOCK_DGRAM
        • Socket库
          • 创建Socket对象
          • Socket对象方法
        • TCP粘包问题
      • APScheduler
      • PyMySQL
      • Redis
    • 后端笔记

  • C笔记

  • C++笔记

  • Arduino笔记

  • Web笔记

  • Dev
  • Python笔记
  • 模块笔记
Hoshinozora
2024-01-06
目录

Socket

# 介绍

Socket又称"套接字",他工作于应用层与传输层之间,本质上是将把TCP、UDP的复杂操作,抽象为简单的几个接口来供应用层调用,实现进程在网络中的数据通信。

# Socket家族

不同的Socket家族,其Socket的地址格式、通信范围、传输性能。常见的Socket家族有AF_INET、AF_INET6、AF_UNIX。

# AF_INET

用于跨主机的网络通信(如互联网或局域网),基于IPv4协议,通过IP地址和端口标识通信端点。

AF_INET数据需经过网络层封装、路由及网卡传输,受带宽和延迟影响,适用于远程通信。

地址格式:(host, port)

host为主机地址,可以是域名或IPv4地址,为空则表示绑定本机的所有网络接口。

port为端口号。

# AF_UNIX

AF_UNIX也称为AF_LOCAL,用于同一台主机上的进程间通信(IPC),通过文件系统路径标识端点,不依赖网络协议。

AF_UNIX直接在内核中拷贝数据,无需网络协议处理,效率更高且不受网络带宽限制。

地址格式:"xxx/xxx/xx"

在文件系统上的socket文件地址,例如:/tmp/socket。

# Socket类型

Socket也分不同的类型,不同的套接字类型使用的传输协议也不同,我们可以根据实际应用场景来选择合适的套接字类型。

# SOCK_STREAM

SOCK_STREAM即流套接字,也叫面向连接的套接字。它基于TCP(传输控制协议) 来提供可靠的、面向连接的服务。

他有如下几个特征:

数据是安全可靠传输的,丢失或错误的数据包会被发送方重传。

数据是作为字节流按照顺序传输的,接收方会根据数据包携带的序列号进行排序。

数据发送方和接收方的调用次数不需要匹配(不保留消息边界)。接收方可以一次读取多次发送的内容,也可以分多次读取一次发送的内容。

# SOCK_DGRAM

SOCK_DGRAM即数据报套接字,也叫无连接的套接字。它基于UDP(用户数据报协议) 提供快速、但不可靠的、无连接服务。

DGRAM是Data Gram的缩写,意为数据报。

他有如下几个特征:

强调快速传输而非可靠,数据可能在传输过程中可能丢失或重复,且无重传机制。

每个数据报文都是独立传输和处理的,不保证顺序到达。

数据发送方和接收方的调用次数需要严格匹配(保留消息边界),每一次发送的数据都会作为一个独立的数据报传输,每一次接收都需要恰好接收一个完整的数据报。

# Socket库

Python中可以使用socket库来实现基本的Socket,它可以访问底层操作系统Socket接口的全部方法。

import socket

# 创建Socket对象

socket.socket(family=AF_INET, type=SOCKET_STREAM)
1

family:套接字家族。

type:套接字类型。

# Socket对象方法

# 服务端方法

方法 描述
s.bind(address) 绑定地址到套接字, 在AF_INET下,地址以元组(host,port)形式表示。host为空字符串则会绑定到所有网络接口。
s.listen(backlog) 开启监听TCP连接。backlog指定在拒绝连接之前,可以挂起的最大连接数量。该值至少为1,大部分应用程序设为5即可。
s.accept() 阻塞并等待客户端连接,客户端成功连接后会停止阻塞并返回元组(客户端对象, 客户端地址)

# 客户端方法

方法 描述
s.connect(address) 向服务器发起连接请求,地址以元组(host,port)形式表示。如果连接出错,则返回socket.error错误。
s.connect_ex(address) 功能与connect相同,但是成功返回0,失败返回error的值。

# 通用方法

方法 描述
s.recv(bufsize[,flag]) 阻塞并等待TCP接受到数据,bufsize指定要接收的最大数据量,flag指定其他设置。
s.send(string[,flag]) 通过TCP发送string中的数据,返回实际发送的数据字节大小。
s.sendall(string[,flag]) 通过TCP尝试发送所有数据,成功返回None,失败则抛出异常。
s.sendto(string[,flag], address) 通过UDP发送数据string,address为数据接收端地址元组(host,port),返回值是发送的字节数。
s.recvfrom(bufsize[,flag]) 阻塞并等待UDP接受到数据,参数与recv()类似,返回值为元组(data,address),其中data为接收的字符串数据,address是发送端的地址。
s.close() 关闭套接字连接。

# 服务端例子

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

address = ("0.0.0.0", 8000)
s.bind(address)
s.listen(5)
print(f"Listen Start: {address}")
while True:
    conn, addr = s.accept()
    print(f"Accept connect: {addr}")
    data = conn.recv(1024).decode("utf-8")
    print(f"Receive data: {data}")
    conn.send("Bye".encode("utf-8"))
    conn.close()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 客户端例子

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("192.168.2.22", 8000))
s.send("Hello".encode("utf-8"))
print(s.recv(1024).decode("utf-8"))
s.close()
1
2
3
4
5
6
7

# TCP粘包问题

# 问题介绍

由于TCP协议基于字节流传输的特性,导致接收方无法区分消息边界,从而可能将多个数据包合并接收或单个数据包拆分接收的现象‌。

# 主流解决方案

为解决消息边界模糊问题,需在应用层设计协议。以下是三种常用方法:

# 固定长度法‌

原理:规定所有数据包长度一致(如64字节),不足时填充空字符。

优点:实现简单,接收方按固定长度分割即可。

缺点:浪费带宽(填充无效数据),灵活性差。‌

# 分隔符法‌

原理:在包尾添加特殊字符(如\r\n)标记结束,接收方按分隔符解析。

优点:易于实现(如FTP协议)。

缺点:需转义数据中可能出现的分隔符,效率较低。‌

# ‌包头+包体法‌(推荐)

原理:包头固定长度(如4字节),存储包体长度字段;接收方先读包头获取长度,再按长度读取包体。

优点:高效灵活,支持变长数据,无冗余传输。

实现示例:

  1. 发送端:将数据封装为[长度字段][数据内容]发送。‌
  2. 接收端:循环读取缓冲区,先解析包头长度,再提取完整包体。‌

可以使用struct模块将数据长度打包为固定大小的字节放在开头发送。解包时先获取固定大小进行解包得到数据长度,再接收指定大小的数据。

#Python#模块#网络通信#Socket
Loguru
APScheduler

← Loguru APScheduler→

最近更新
01
Vue路由
12-09
02
FastAPI实现用户管理
11-23
03
Tortoise ORM
11-23
更多文章>
Theme by Vdoing | Copyright © 2022-2026 Hoshinozora | MIT License
湘ICP备2022022820号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式