当前位置: 首页 > web >正文

网络编程---TCP协议

TCP协议基础知识

TCP(Transmission Control Protocol,传输控制协议)是互联网核心协议之一,位于传输层(OSI第4层),为应用层提供可靠的、面向连接的、基于字节流的数据传输服务。它与IP协议共同构成TCP/IP协议栈的基础。

TCP的核心特性

  • 面向连接

    • 通信前需通过三次握手建立连接,结束后通过四次挥手释放连接。

    • 每个连接由四元组(源IP、源端口、目的IP、目的端口)唯一标识。

  • 可靠性

    • 序列号与确认应答(ACK):每个字节数据都有编号,接收方通过ACK确认已收到的数据。

    • 超时重传:未收到ACK时,发送方会重传数据。

    • 数据校验:通过校验和(Checksum)检测传输错误。

    • 流量控制:通过滑动窗口机制动态调整发送速率,避免接收方缓冲区溢出。

    • 拥塞控制:通过算法(如慢启动、拥塞避免、快重传、快恢复)防止网络过载。

  • 字节流服务

    • 应用层数据被TCP视为无结构的字节流,不保留消息边界(需应用层自行解析,如HTTP的Content-Length或分块传输)。

  • 全双工通信

    • 连接双方可同时发送和接收数据。

TCP协议报文结构

字段名位数/字节数说明
源端口16 位发送端的端口号
目的端口16 位接收端的端口号
序号(seq)32 位本报文段第一个字节的序列号
确认号(ack)32 位期望收到的下一个字节序号
数据偏移4 位TCP首部长度(单位:4字节),最大60字节
保留6 位保留字段,必须为0
控制位6 位包括 URG、ACK、PSH、RST、SYN、FIN
窗口16 位接收窗口大小(流量控制)
检验和16 位校验TCP首部和数据
紧急指针16 位在 URG=1 时有效,指出紧急数据的末尾

  • 1.ACK(Acknowledgment 标志位) 是控制位里的一个“开关”。
  • 只有 ACK=1 时,32 bit 数字才有效。 
  • 2.确认号(Acknowledgment Number) 是一个 32 bit 的“数值”。
  • 期望收到的下一个字节序号
  • 换句话说,它表示“序号 ≤ 确认号-1 的所有字节我都收齐了”。
  • 只有当 ACK = 1 时才有效。

eg:

ACK=1, Ack=1001 含义:
“我(接收方)已经收到了 1000 及以前的全部数据,请你(发送方)下一帧从 1001 开始发。”

TCP首部(可变部分)
  • 选项(Options):长度可变(最多40字节),常见选项包括:

    • MSS(最大报文段长度)

    • 时间戳(Timestamps)

    • 窗口扩大因子(Window Scale)

  • 填充(Padding):用于补齐至4字节倍数

TCP数据部分
  • 实际传输的应用层数据(如HTTP请求、FTP命令等)

整体结构层次

  • IP首部:包含源/目的IP地址、TTL、协议类型(TCP=6)等

  • IP数据部分:整个TCP报文段(TCP首部 + TCP数据)

TCP--三次握手和四次挥手

TCP协议的三次握手和四次挥手是TCP建立和断开连接的两个重要过程,它们确保了数据传输的可靠性和连接的正确管理。

一、三次握手

定义: 三次握手(Three-way Handshake)是TCP协议用来建立可靠连接的过程。它需要客户端和服务器之间发送三个数据包来完成连接的建立。

目的

  • 确认双方的接收能力和发送能力是否正常。

  • 同步双方的序列号(Sequence Number)和确认号(Acknowledgment Number)。

  • 为后续的可靠传输做准备。

过程 设客户端为A,服务器端为B

步骤发送方接收方描述
第一次握手ABA向B发送一个SYN报文,标志位SYN=1,序列号seq=x。表示A希望与B建立连接。
第二次握手BAB收到A的SYN报文后,发送一个SYN+ACK报文作为响应。SYN=1,ACK=1,序列号seq=y,确认号ack=x+1。表示B同意连接,并将A的序列号加1确认。
第三次握手ABA收到B的SYN+ACK报文后,发送一个ACK报文。ACK=1,序列号seq=x+1,确认号ack=y+1。表示A确认收到B的响应,连接建立完成。

为什么需要三次握手?

三次握手的主要目的是防止失效的连接请求报文突然到达服务器,从而产生错误。如果采用两次握手,可能会出现以下问题:

  • 客户端发送的连接请求报文可能因为网络延迟而滞留,未能及时到达服务器。

  • 当客户端再次发送连接请求并成功建立连接后,第一次发送的报文可能突然到达服务器。

  • 如果采用两次握手,服务器会误认为客户端又发送了一次连接请求,从而建立一个无效的连接。

  • 这种情况下,客户端会忽略服务器的确认,也不发送数据,导致不必要的错误和网络资源浪费。

  • 而采用三次握手,即使失效的报文到达服务器,服务器会发送确认报文,但客户端不会确认,服务器因此知道客户端没有请求连接。

二、四次挥手

定义: 四次挥手(Four-way Wavehand)是TCP协议用来断开连接的过程。它需要客户端和服务器之间发送四个数据包来确认连接的断开。

过程 设客户端为A,服务器端为B

步骤发送方接收方描述
第一次挥手ABA发送一个FIN报文,标志位FIN=1,表示A希望关闭连接。A进入FIN_WAIT_1状态。
第二次挥手BAB收到A的FIN报文后,发送一个ACK报文作为响应。ACK=1,确认号ack为A的序列号加1。B进入CLOSED_WAIT状态。
第三次挥手BAB在处理完未完成的发送请求后,发送一个FIN报文给A,表示B也准备关闭连接。B进入LAST_ACK状态。
第四次挥手ABA收到B的FIN报文后,发送一个ACK报文作为响应。ACK=1,确认号ack为B的序列号加1。A进入TIME_WAIT状态。B进入CLOSED状态,完成连接关闭。
客户端状态变化A在经过2MSL(最大报文段生存时间)后,进入CLOSED状态,完成连接关闭。

为什么需要四次挥手?

  • 在TCP连接中,数据的发送是双向的,客户端和服务器可能都有未发送或未接收的数据。

  • 当一方(如客户端)发送FIN报文请求关闭连接时,另一方(如服务器)可能还有未处理完的数据。

  • 因此,服务器需要先发送ACK确认收到关闭请求,然后在处理完数据后再发送自己的FIN报文。

  • 客户端收到服务器的FIN报文后,也需要发送ACK确认,确保服务器知道客户端已经收到关闭请求。

  • 这样,双方都需要两次确认,因此总共需要四次挥手。

客户端为什么要等待2MSL?

  • 2MSL(两倍最大报文段生存时间)是任何报文在网络上存在的最长时间。

  • 客户端在发送最后一个ACK报文后,需要等待2MSL时间,以确保这个ACK报文能够到达服务器。

  • 如果ACK报文丢失,服务器会重新发送FIN报文,客户端可以再次发送ACK报文。

  • 等待2MSL时间可以确保旧连接的报文不会影响新连接的建立。

三、总结

  • 三次握手:用于建立TCP连接,确保双方的发送和接收能力正常,同步序列号和确认号。

  • 四次挥手:用于断开TCP连接,确保双方都处理完未完成的发送请求,安全地关闭连接。

  • 三次握手的原因:防止失效的连接请求报文导致错误连接。

  • 四次挥手的原因:确保双方都能处理完未完成的发送请求,避免数据丢失或错误。

通过三次握手和四次挥手,TCP协议能够实现可靠、有序、无丢失的数据传输。

TCP数据传输

可靠传输保障------四大机制 + 三类算法 + 两套定时器

TCP 通过“编号-确认-重传-窗口-校验”四大机制,辅以“滑动窗口、流量控制、拥塞控制”三类算法,加上“重传定时器、持续定时器”两套计时器,实现 100 % 可靠、按序、无差错的数据传输。

一、四大机制:可靠传输的基础保障 

1. 编号机制:给每一个字节 “贴标签”,实现按序重组

TCP 是 “面向字节流” 的协议(应用层发送的是字节流,而非独立报文),为了让接收方能够识别数据的顺序和完整性,TCP 会给每一个字节分配唯一的编号(序号)。

  • 具体规则:发送方发送的每个报文段的 “序号” 字段,是该报文段中第一个字节的编号。例如,若发送方已发送到字节 100,下一个报文段包含字节 101-200,则该报文段的序号为 101。
  • 作用:接收方通过序号判断数据的先后顺序,即使报文段因网络延迟乱序到达,也能通过序号重新排序;同时,序号能帮助接收方识别重复数据(如因重传导致的重复报文段)并丢弃。

2. 确认机制:接收方 “回信”,告知发送方 “已收到”

为了让发送方知道数据是否被正确接收,TCP 采用 “确认(ACK)机制”:接收方收到数据后,会发送一个 “确认报文段”(ACK 报文),告知发送方 “哪些数据已正确接收”。

  • 确认号规则:ACK 报文的 “确认号” 字段,是接收方期望收到的下一个字节的编号。例如,若接收方已正确收到字节 1-100,则确认号为 101(表示 “我已收到 100 及之前的所有数据,下次请发 101 开始的字节”)。
  • 累积确认:TCP 默认使用 “累积确认”(Cumulative ACK),即只要连续收到数据,就只需要确认最后一个连续字节的下一个序号,无需对每个报文段单独确认,减少 ACK 报文数量,提高效率。
  • 补充:若接收方收到不连续的数据(如丢失中间报文段),会发送 “重复 ACK”(确认号不变),触发发送方快速重传(见下文 “重传机制”)。

3. 重传机制:数据丢失?“补送” 一次

当数据或确认报文(ACK)因网络故障丢失时,发送方需要重新发送数据,这一过程由 “重传机制” 实现。重传的触发有两种常见场景:

  • 超时重传:若发送方在 “重传定时器” 到期前未收到 ACK(假设数据或 ACK 丢失),则重传该报文段。
  • 快速重传:若发送方收到3 个连续的重复 ACK(表示接收方收到了乱序数据,且中间有数据丢失),则无需等待超时,立即重传丢失的报文段(减少重传延迟)。

4. 校验机制:过滤 “损坏” 的数据,确保无差错

TCP 通过 “校验和” 验证数据在传输过程中是否被损坏(如比特错误、篡改),是 “无差错传输” 的核心保障。

  • 计算方式:发送方在发送前,对 TCP 报文段的 “首部 + 数据 + 伪首部”(伪首部包含源 IP、目的 IP 等,确保端到端正确性)计算校验和,并填入 TCP 首部的 “校验和” 字段;
  • 验证方式:接收方收到报文段后,重新计算校验和,若与首部的校验和不一致,说明数据损坏,会直接丢弃该报文段(不发送 ACK),导致发送方重传。

二、三类算法:优化传输效率,平衡速度与稳定性

四大机制确保了 “可靠性”,但单纯依赖机制可能导致传输效率低下(如发送方等待每个 ACK 后再发下一个数据)。三类算法通过动态调整发送速率,在可靠的基础上提升效率,同时避免 “过载”。

1. 滑动窗口算法:批量传输的 “效率引擎”

滑动窗口是 TCP 实现 “批量传输” 和 “动态控制” 的基础,其核心是通过 “窗口大小” 限制发送方的发送范围,实现 “无需等待每个 ACK 即可连续发送”。

  • 窗口定义:发送方的 “发送窗口” 是当前可发送数据的范围(由序号标识),窗口内的字节可以连续发送,无需等待逐个确认;窗口外的字节需等待窗口滑动后才能发送。
  • 窗口滑动:当发送方收到 ACK 时,发送窗口会 “向前滑动”(窗口左边界右移),新的字节进入窗口,可被发送。例如,发送窗口初始范围是 1-100,收到确认号 101 的 ACK 后,窗口滑动为 101-200。
  • 作用:结合编号和确认机制,实现 “流水线式” 传输,大幅提升传输效率(避免 “停 - 等” 模式的低效)。

2. 流量控制算法:防止 “接收方被撑爆”

流量控制的目标是避免发送方发送过快,导致接收方缓冲区溢出(接收方处理速度跟不上发送速度)。其核心是接收方通过 “窗口字段” 告知发送方自己的接收能力。

  • 原理:接收方在 TCP 首部的 “窗口” 字段(接收窗口,rwnd)中,告知发送方自己当前的缓冲区剩余容量(即最多还能接收多少字节);发送方的 “发送窗口大小” 不能超过 rwnd(确保接收方来得及处理)。
  • 特殊场景:若接收方缓冲区满了(rwnd=0),发送方会暂停发送;待接收方处理完数据、缓冲区有空闲后,会发送 “窗口更新报文”(rwnd>0),发送方恢复发送。

3. 拥塞控制算法:防止 “网络被堵死”

拥塞控制的目标是避免发送方发送过快,导致网络拥塞(如路由器缓冲区溢出、丢包)。其核心是通过 “拥塞窗口(cwnd)” 动态调整发送速率,cwnd 的大小由网络状况决定。

  • 核心逻辑:发送方的实际发送窗口大小 = min(接收窗口 rwnd,拥塞窗口 cwnd),既受接收方能力限制,也受网络拥塞状况限制。
  • 关键阶段:
    • 慢启动:连接初始时,cwnd 从 1 个报文段开始,每收到一个 ACK 就翻倍(指数增长),快速提升速率至 “拥塞阈值(ssthresh)”;
    • 拥塞避免:当 cwnd 超过 ssthresh 后,每轮 RTT(往返时间)cwnd 只增加 1 个报文段(线性增长),避免网络拥塞;
    • 快速重传与恢复:若收到 3 个重复 ACK(表示轻微拥塞),则立即重传丢失报文,同时将 ssthresh 设为当前 cwnd 的一半,cwnd 设为 ssthresh(快速恢复,避免骤降);
    • 超时重传:若超时(表示严重拥塞),则将 ssthresh 设为当前 cwnd 的一半,cwnd 重置为 1,重新进入慢启动。

三、两套定时器:解决 “超时” 和 “死锁” 问题

定时器是 TCP 处理异常场景的 “保险装置”,确保在数据丢失、窗口冻结等情况下,传输仍能正常推进。

1. 重传定时器:检测 “数据或 ACK 丢失”,触发重传

  • 作用:当发送方发送一个报文段后,立即启动重传定时器;若在定时器到期前收到对应的 ACK,则关闭定时器;若未收到,则判定数据或 ACK 丢失,触发重传。
  • 超时时间(RTO):RTO 并非固定值,而是基于 “往返时间(RTT,数据发送到收到 ACK 的时间)” 动态计算(如使用加权平均 RTT 和偏差值),确保 RTO 既能及时检测丢失,又不会因网络延迟误判(避免频繁无效重传)。

2. 持续定时器:解决 “窗口为 0 导致的死锁”

  • 场景:当接收方缓冲区满(rwnd=0)时,发送方会停止发送数据;若后续接收方处理完数据,发送 “窗口更新报文(rwnd>0)” 但该报文丢失,发送方会一直等待,形成 “死锁”。
  • 作用:当接收方告知 rwnd=0 时,发送方启动持续定时器;定时器到期后,发送方发送一个 “窗口探查报文”(1 字节数据),接收方收到后会回复当前的 rwnd(无论是否为 0),若 rwnd>0,发送方恢复发送,打破死锁。
机制作用关键点
序列号 / 确认号字节编号 + 累积确认每个字节都有序号(seq);ack = 期望收到的下一个字节号
重传丢包恢复超时重传(RTO)、快速重传(3 个重复 ACK)
校验和差错检测首部和数据一起反码求和;出错即丢弃
窗口批量确认允许连续发多帧而不必每帧都等 ACK,提高吞吐
算法控制对象典型策略
滑动窗口(Sliding Window)接收方缓存接收窗口 rwnd 告诉发送方“我还能收多少”
流量控制(Flow Control)端到端速率根据 rwnd 调整发送窗口,避免撑爆接收缓存
拥塞控制(Congestion Control)网络拥塞慢启动、拥塞避免、快重传、快恢复,用 cwnd 探测可用带宽

发送窗口大小 = min(rwnd, cwnd) 

定时器触发时机动作
重传定时器每发一个未被确认的段RTO 内未收到 ACK → 重传
持续定时器收到零窗口通告周期性探测,防止窗口死锁
  • 编号确认:字节有序号,ack 指下一字节

  • 重传机制:超时 & 快速重传

  • 流量控制rwnd 防止接收端溢出

  • 拥塞控制cwnd 防止网络崩溃

  • 校验和:检错即丢

  • 定时器:超时重传 + 零窗口探测

TCP 粘包

产生TCP粘包的原因:

发送方原因

  • Nagle 算法:Nagle 算法是 TCP 协议中的一种优化机制,其目的是减少网络中微小分组的数量,提高网络利用率。该算法规定,当发送方应用程序调用 send () 函数发送数据时,如果发送缓冲区中存在未被确认的字节,那么新的数据会被缓存起来,直到缓冲区中的数据被确认或者缓冲区被填满,才会将数据发送出去。这样一来,就可能导致多个小数据被合并成一个大的数据块发送,进而产生粘包。
  • 发送缓冲区机制:发送方应用程序不断调用 send () 函数发送数据时,这些数据会先被放入操作系统的发送缓冲区中。如果发送的数据量较小,且发送频率较高,操作系统可能会将这些小数据组合在一起进行发送,从而造成粘包。

接收方原因

  • 接收缓冲区机制:接收方通过 recv () 函数从操作系统的接收缓冲区中读取数据。当接收缓冲区中的数据量达到一定程度,或者应用程序调用 recv () 函数的频率较低时,可能会一次性读取到多个原本独立的数据包,表现为粘包现象 。例如,接收方缓冲区一次可以容纳 1024 字节数据,而发送方先后发送了两个 512 字节的数据包,接收方在读取时可能就将这两个数据包当作一个整体读取,造成粘包。

解决方法

  • 消息定长法规定每个数据包的长度固定,接收方每次从接收缓冲区中读取固定长度的数据作为一个完整的数据包。不过,这种方法在消息较短时会造成一定的空间浪费。
  • 包头包体法在每个数据包前加上一个包头,包头中包含该数据包的长度等信息,包体则是实际的数据内容。接收方先读取包头,获取数据包的长度,再根据长度读取对应的包体数据。
  • 特殊分隔符法在数据包之间添加特殊的分隔符,接收方通过查找分隔符来确定数据包的边界。增加了实现的复杂性。

使用套接字Socket常用函数(Linux系统为例)

套接字(Socket)是网络编程中用于实现不同主机或同一主机上不同进程间网络通信的抽象接口,是操作系统提供的一种进程间通信机制,本质上是内核中的一个数据结构,用于管理网络连接和数据传输。

套接字是连接网络应用程序与底层协议的桥梁,它隐藏了网络传输的复杂细节,让开发者能更简单地实现进程间的网络通信。

编程接口角度
套接字是应用程序与操作系统内核网络协议栈之间的接口。开发者通过调用socket()等系统函数创建套接字,再通过bind()connect()send()recv()等函数操作它,实现数据的发送和接收,无需直接处理复杂的底层协议(如 TCP 握手、IP 路由等)。

通信端点角度
套接字可视为网络通信的 “端点”。一次网络通信需要两个端点(如客户端和服务端各有一个套接字),数据通过这两个端点在网络中流转。每个端点由 “IP 地址 + 端口号” 标识,再结合协议类型(如 TCP/UDP),构成唯一的 “五元组”,确保数据能准确送达目标进程。

操作系统抽象角度
在 Unix/Linux 系统中,套接字被抽象为 “文件描述符”(类似文件、管道的标识),遵循 “一切皆文件” 的设计哲学。这意味着可以用操作文件的方式(如read()write()close())来操作套接字,简化了网络编程模型。

协议关联角度
套接字与具体的网络协议绑定,创建时需指定协议族(如 IPv4 的AF_INET)、套接字类型(如 TCP 的SOCK_STREAM、UDP 的SOCK_DGRAM)等,决定了通信的规则(如是否可靠、是否面向连接)。

socket() creates an endpoint for communication and returns a file descriptor that refers to that endpoint. The file descriptor returned by a successful call will be the lowest-numbered file descriptor not currently open for the process.

socket () 函数创建一个通信端点,并返回一个引用该端点的文件描述符。成功调用后返回的文件描述符,将是当前进程中未打开的编号最小的文件描述符。

RETURN VALUE
On success, a file descriptor for the new socket is returned.  On error, -1 is returned, and errno is set appropriately.

成功时,返回新套接字的文件描述符。失败时,返回 -1,并适当设置 errno(错误码)。

#include <sys/socket.h>
int socket(int domain, int type, int protocol);说明:
domain:指定网络协议族(如 AF_INET 对应 IPv4,AF_INET6 对应 IPv6 ),决定 “用什么网络体系通信”;
type:指定套接字类型(如 SOCK_STREAM 对应 TCP 流式套接字,SOCK_DGRAM 对应 UDP 数据报套接字 ),决定 “通信的传输模式”;
protocol:一般填 0,让系统自动匹配 domain + type 对应的默认协议(如 AF_INET + SOCK_STREAM 自动选 IPPROTO_TCP )。

调用后,系统会在内核中 创建一个套接字对象,并返回一个整数 “套接字描述符”(类似文件描述符)。后续所有网络操作(绑定、连接、收发数据),都通过这个描述符操作 “内核里的套接字对象”,是网络编程的第一步。 

套接字的完整标识是 “五元组”:{ 源IP, 源端口, 目的IP, 目的端口, 协议 }

服务端调用 bind() 时,会绑定 (源IP, 源端口, 协议)

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);struct sockaddr{sa_family_t sa_family;char        sa_data[14];
}
struct sockaddr_in {sa_family_t    sin_family; /* address family: AF_INET */in_port_t      sin_port;   /* port in network byte order */struct in_addr sin_addr;   /* internet address */
};
sockfd:通过 socket() 函数创建的套接字文件描述符,即需要被绑定的套接字。
addr:const struct sockaddr *(通常需要强转为特定协议的地址结构,如 struct sockaddr_in 用于 IPv4)指向包含 “要绑定的 IP 地址和端口号” 的地址结构指针。以 IPv4 为例,实际使用的是 struct sockaddr_in 结构(需强制转换为 struct sockaddr * 类型传入)
addrlen:addr 指向的地址结构的大小(字节数),通常用 sizeof(struct sockaddr_in) 获取。

客户端调用 connect() 时,会指定 (目的 IP, 目的端口, 协议)

#include <sys/types.h>          /* See NOTES *
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
connect () 系统调用将文件描述符 sockfd 所指向的套接字,连接到 addr 所指定的地址。addrlen 参数指定了 addr 的大小。addr 中地址的格式由套接字 sockfd 的地址空间决定
RETURN VALUEIf the connection or binding succeeds, zero is returned.  On error, -1 is returned, and errno is set appropriately.

监听 listen()

将 sockfd 标识的套接字转换为监听套接字(进入 LISTEN 状态),使其具备接收客户端 connect() 请求的能力。listen () 函数将 sockfd 所指向的套接字标记为被动套接字,即该套接字将用于通过 accept () 函数接收传入的连接请求。

  • 被动套接字(passive socket):服务端特有的套接字状态,与客户端的 “主动套接字”(发起连接)相对。被动套接字的唯一作用是监听并接收客户端的连接请求,不直接参与数据传输。
  • 与 accept (2) 的关联:被 listen () 标记为被动的套接字,必须配合 accept () 使用 ——accept () 会从该套接字的连接队列中取出已完成的连接,创建新的套接字用于实际的数据收发(监听套接字本身仍继续接收新请求)。
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int listen(int sockfd, int backlog);
backlog:指定未完成连接队列(处于 SYN_RCVD 状态)和已完成连接队列(处于 ESTABLISHED 状态)的总长度上限。
未完成连接:客户端发送 SYN 后,三次握手未完成的连接
已完成连接:三次握手完成,等待服务端调用 accept() 接收的连接
实际值:系统会根据内核参数(如 net.core.somaxconn)对 backlog 进行限制,通常取 5 到 128(高并发场景可能更大)

发送 send() 

send () 调用仅能在套接字处于已连接状态时使用(此时目标接收方是已知的)。send () 与 write (2) 的唯一区别在于是否存在 flags 参数。当 flags 参数为 0 时,send () 与 write (2) 功能等价。

#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
flags:发送选项标志,通常设为 0(默认行为)
常用标志包括:
MSG_OOB:发送带外数据(用于 TCP 紧急数据传输)
MSG_DONTWAIT:非阻塞发送(即使缓冲区满也不阻塞,立即返回)
MSG_NOSIGNAL:发送失败时不产生 SIGPIPE 信号(避免进程被终止)

接受收recv()

从 sockfd 标识的套接字接收数据,并将数据存入 buf 缓冲区,最多接收 len 字节。

#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
flags:接收选项标志,通常设为 0(默认行为)。
常用标志包括:
MSG_OOB:接收带外数据(TCP 紧急数据)
MSG_PEEK:预览数据(读取数据但不从内核缓冲区移除,可用于查看数据而不消费)
MSG_WAITALL:阻塞等待直到接收满 len 字节(或发生错误 / 连接关闭)
MSG_DONTWAIT:非阻塞接收(无数据时立即返回,不阻塞)

结语:

无论你是初学者还是有经验的开发者,我希望我的博客能对你的学习之路有所帮助。如果你觉得这篇文章有用,不妨点击收藏,或者留下你的评论分享你的见解和经验,也欢迎你对我博客的内容提出建议和问题。每一次的点赞、评论、分享和关注都是对我的最大支持,也是对我持续分享和创作的动力

http://www.xdnf.cn/news/16129.html

相关文章:

  • 跨越语言壁垒!ZKmall开源商城多语言架构如何支撑电商全球化布局
  • libgmp库(GNU高精度算术库)介绍
  • mac实现sudo命切换node版本
  • netty的编解码器,以及内置的编解码器
  • OpenCV 零基础到项目实战 | DAY 1:图像基础与核心操作
  • LLC协议
  • mysql_innodb_cluster_metadata源数据库
  • Vue3 面试题及详细答案120道(31-45 )
  • Web3面试题
  • 智慧能源合同解决方案
  • 【接口自动化】pytest的基本使用
  • XML高效处理类 - 专为Office文档XML处理优化
  • Aspose.Cells 应用案例:法国能源企业实现能源数据报告Excel自动化
  • Python通关秘籍(五)数据结构——元组
  • Rocky Linux 9 快速安装 Node.js
  • 3.5 模块化编程实践
  • 【数据结构初阶】--栈和队列(二)
  • Python之格式化Conda中生成的requirements.txt
  • 我的第一个开源项目 -- 实时语音识别工具
  • 数据库表介绍
  • 算法提升之字符串回文处理-(manacher)
  • 自编码器表征学习:重构误差与隐空间拓扑结构的深度解析
  • 客户案例 | Jabil 整合 IT 与运营,大规模转型制造流程
  • 《小白学习产品经理》第八章:方法论之马斯洛需求层次理论
  • Java新特性-record
  • 力扣-139.单词拆分
  • js的基本内容:引用、变量、打印、交互、定时器、demo操作
  • 网络安全基础作业三
  • lspci/setpci用法小结
  • SpringBoot--Mapper XML 和 Mapper 接口在不同包