Unix网络编程

一个简单的时间获取客户端程序

把上面的ipv4协议换成ipv6,加粗字体需要替换

一个简单的时间获取服务器程序

accept函数

1. 默认行为(阻塞模式)

当你创建一个 socket,使用 bind 和 listen 后,默认的套接字是阻塞的。此时调用 accept:

  • 如果已完成连接队列 (已完成三次握手的连接)为空,accept 会阻塞当前线程,直到有新的客户端连接到来。

  • 当有新连接时,accept 返回一个新的已连接套接字(connected socket)。

2. 非阻塞模式

你可以通过以下方式将监听套接字设置为非阻塞 ,此时 accept 变为非阻塞:

  • 如果连接队列为空,accept 不会等待,而是立即返回 -1,并设置 errno 为 EAGAIN 或 EWOULDBLOCK。

  • 在 Linux 下 ,你还可以在创建 socket 时使用 SOCK_NONBLOCK 标志,或者使用 fcntl 设置 O_NONBLOCK 属性。

UDP套接字

客户端可以通过同一个套接字发送给不同的服务端

这是因为 UDP 是无连接的协议 ,UDP 套接字本身不维护与对端之间的固定连接状态。你可以把一个 UDP 套接字想象成一个"邮箱":它只需要绑定到本地地址和端口,之后每次发送数据时,在 sendto 或 sendmsg 调用中明确指定目标地址(IP + 端口),就可以将数据发往任意不同的服务端。


具体原因

  1. 无连接特性

    UDP 在传输层不建立连接,每个数据报都是独立发送的。内核只根据你提供的目标地址来封装 IP 头和 UDP 头,不需要像 TCP 那样先建立连接并维护状态。

  2. 套接字与目标地址的分离

    • 在 TCP 中,一个套接字一旦通过 connect 连接到某个服务端,内核就会为该套接字固定对端的 IP 和端口,之后只能用 send/write 发送,不能再改变目标。

    • 在 UDP 中,即使你调用了 connect(UDP 的 connect 只是在内核中缓存了默认目标地址,并不建立真实连接),你仍然可以使用 sendto 覆盖该默认目标,发送到其他地址。未调用 connect 的 UDP 套接字更是完全自由。

  3. 内核的实现

    UDP 套接字在内核中只记录本地地址和端口,发送数据时,从用户空间传入的目标地址被直接用于构造数据报。内核不会因为发送到不同服务端而创建新的套接字或改变原有套接字的状态。

UDP可以不使用connect

UDP 使用 sendto 与 connect 的区别

特性 不使用 connect 使用 connect
发送方式 必须用 sendto 指定目标地址 可以用 send / write(目标地址已缓存)
接收方式 用 recvfrom 获取发送方地址 可以用 recv / read,但 recvfrom 也能用
地址绑定 每次发送都指定目标,可发往不同地址 只与一个固定地址"绑定",但可以通过 sendto 覆盖
内核开销 每次发送都需复制目标地址 内核缓存目标地址,减少一次地址复制
错误报告 异步错误(如端口不可达)可能延迟返回 同步错误,部分错误会立即返回给 send

为什么不使用 connect 更灵活?

因为 UDP 是无连接的,一个 UDP 套接字可以在不同时间向不同的服务端发送数据,无需重新创建套接字。这在需要与多个对端通信的场景(如 DNS 客户端、P2P 应用)中非常方便。

那什么时候用 connect?

  1. 只与一个固定服务端通信(如传统的 UDP 客户端/服务器模型)。

  2. 希望简化代码 :send/recv 比 sendto/recvfrom 少写参数。

  3. 需要接收异步错误 :connect 后,某些错误(如 ICMP 端口不可达)会直接传递给套接字,而不是在后续的 sendto 中才被感知。

  4. 性能敏感场景:减少内核中每次发送时的地址处理开销。

注意:connect 并不改变 UDP 的无连接本质

即使对一个 UDP 套接字调用了 connect,你依然可以通过 sendto 发往其他地址(除非设置 IP_FREEBIND 等特殊选项)。但通常不建议混合使用,以免造成混淆。

TCP套接字

1. 流量控制(Flow Control)

  • 目的:防止发送方发送数据过快,导致接收方缓冲区溢出而丢包。

  • 实现机制 :滑动窗口。接收方通过 TCP 报文头中的"窗口"字段告知发送方自己当前还能接收多少字节的数据(可用窗口大小)。发送方根据这个窗口值动态调整发送速率。

  • 特点:这是端到端的控制,确保发送方的发送速度匹配接收方的处理能力。


2. 排序(Ordering / Sequencing)

  • 目的:保证数据在到达接收端后,能按照发送时的顺序重组。

  • 实现机制 :序列号。TCP 将应用层交付的数据分割成若干段(Segment),并为每个字节分配一个序号。接收方根据序号将乱序到达的数据重新排序,并去除重复数据。

  • 特点:这是 TCP 可靠传输的重要保障,解决了 IP 层可能产生的乱序和重复问题。


3. 全双工(Full-Duplex)

  • 含义 :TCP 连接允许数据在两个方向上同时独立地传输。即 A 向 B 发送数据的同时,B 也可以向 A 发送数据。

  • 实现方式:每个 TCP 连接在双方各自维护一个发送缓冲区和接收缓冲区。两个方向的传输互不干扰,由独立的序列号空间和窗口大小分别管理。

  • 优势:提高了交互式应用的响应速度,例如在 HTTP 请求/响应、远程登录等场景下,双方可以同时发送数据。

三次握手

上面这个打电话的例子非常好

相关推荐
Ruiery1 小时前
Linux 6.6内核并发与同步(五):mutex 可睡眠锁
linux·运维·服务器
开开心心就好2 小时前
竖式除法出题工具,整除余数混合模式
运维·服务器·前端·javascript·ocr·perl·1024程序员节
updayday8542 小时前
客户附件不该发往旧邮箱,如何在发送前拦截 - Ping64 邮件安全管控
大数据·网络·数据库·安全·智能路由器
其实防守也摸鱼2 小时前
Chrome 扩展安全攻防实录:从攻击面到防御实践
开发语言·前端·网络·chrome·安全·web安全·php
小茬粥2 小时前
QEMU 宿主机网卡实例发现与采集脚本(标准 Linux / Proxmox VE 适配版)COLT_CMDB_QEMU_IFACE.sh
网络
见合八方3 小时前
借助半导体光放大器实现功率预算超31dB的112.5Gbit/s长距无源光网络
网络·5g·soa·光通信·激光雷达·半导体光放大器
程序猿老A3 小时前
轻量应用服务器总是CPU 100%怎么办?
服务器
夜雪一千3 小时前
锐捷天蝎路由器WiFi优化设置教程:解决邻居WiFi干扰、远距离卡顿
网络·智能路由器
2301_780789663 小时前
深度伪造即服务:新型网络诈骗的“完美面具”与识别之道
java·网络·ddos
余额瞒着我当琳4 小时前
Linux初识:Linux的历史,计算机的发展脉络,发行版本,选购云服务器,安装Xshell,第一次连接,基础命令指南
linux·运维·服务器