跳到主要内容
极客日志极客日志
首页博客AI提示词GitHub精选代理工具
搜索
|注册
博客列表

目录

  1. 一、Socket 编程是什么
  2. 二、UDP Socket 编程核心特点
  3. 三、UDP Socket 编程核心接口(Linux 下 C/C++)
  4. 1. socket() —— 创建套接字描述符
  5. 2. bind() —— 绑定 IP 与端口
  6. 3. sendto() —— 发送数据报
  7. 4. recvfrom() —— 接收数据报
  8. 5. close() —— 关闭套接字
  9. 四、UDP Socket 编程基本流程
  10. 服务端流程(固定步骤)
  11. 客户端流程(固定步骤)
  12. 五、核心网络字节序转换接口
C++

Linux Socket 套接字编程基础概念

介绍 Linux 环境下 Socket 套接字编程基础,重点阐述 UDP Socket 特性与核心接口。内容涵盖 Socket 概念、TCP 与 UDP 的区别、UDP 无连接及面向数据报的特点。详细解析了 socket、bind、sendto、recvfrom、close 五个关键函数的用法及参数,并介绍了主机字节序与网络字节序的转换方法。最后总结了服务端与客户端的标准编程流程,为后续网络通信实战打下基础。

城市逃兵发布于 2026/3/26更新于 2026/4/184 浏览

一、Socket 编程是什么

Socket(套接字)是网络通信的编程接口,是应用层与 TCP/IP 协议族通信的中间软件抽象层。简单来说,它是两个网络程序之间实现数据传输的'桥梁'。无论是 TCP 还是 UDP 协议,都可以通过 Socket 接口实现跨主机、跨网络的进程间通信,也是实现网络编程的基础核心。

Socket 编程主要分为TCP Socket和UDP Socket两类:

  • TCP Socket:基于面向连接的 TCP 协议,提供可靠、有序、字节流的传输,适用于文件传输、登录认证等对数据可靠性要求高的场景。
  • UDP Socket:基于无连接的 UDP 协议,提供无可靠保证、面向数据报的传输,传输速度快、开销小,适用于聊天、音视频传输、广播等对实时性要求高的场景。

本文重点讲解UDP Socket的核心基础与常用接口,TCP Socket 将在后续补充。

二、UDP Socket 编程核心特点

UDP 是无连接的传输层协议,决定了 UDP Socket 编程的核心特性,也是与 TCP Socket 的核心区别:

  1. 无连接:通信双方无需提前建立连接,客户端直接向服务端发送数据报,服务端直接接收即可。
  2. 面向数据报:数据以'数据报'为单位传输,每次发送/接收都是一个完整的数据报,数据报大小有限制(通常小于 64K)。
  3. 无需维护连接状态:服务端可同时接收多个客户端的数据,无需为每个客户端维护连接,资源开销小。
  4. 无可靠保证:数据传输可丢失、乱序,UDP 协议不提供重传、确认机制,可靠性由应用层自行实现。
  5. 全双工通信:一个 Socket 描述符(fd)既可以用于读取数据,也可以用于写入数据,支持同时收发。

三、UDP Socket 编程核心接口(Linux 下 C/C++)

UDP Socket 编程的接口均来自 Linux 系统的网络编程头文件,核心头文件包含:

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>

所有接口的返回值均为int/ssize_t,返回 -1 表示调用失败,可通过 errno 和 strerror(errno) 查看错误原因。

1. socket() —— 创建套接字描述符

功能:创建一个 Socket 描述符,作为后续网络通信的句柄,相当于打开一个'网络文件'。

函数原型:

 ;
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog

更多推荐文章

查看全部
  • ADI SHARC C/C++ 编译器指令优化
  • Claude Code 在 macOS 上的安装与更新指南
  • Python Pandas 安装踩坑与解决方案
  • Copilot Chat 功能介绍与使用指南
  • MySQL JDBC 基础与使用详解
  • Unity 与 Python 互通入门:点击按钮调用 Python
  • 前端安全实战:防御 XSS、CSRF 及敏感信息保护
  • Ubuntu 18.04 解决 Linux 5.4 下 Intel I226-V 2.5G 网卡驱动识别问题

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online

int
socket
(int domain, int type, int protocol)

参数说明:

  • domain:协议域,指定网络层协议,UDP/TCP 均使用 AF_INET(IPv4 协议);
  • type:套接字类型,UDP 使用 SOCK_DGRAM(数据报套接字),TCP 使用 SOCK_STREAM(字节流套接字);
  • protocol:指定具体协议,填 0 表示根据 domain 和 type 自动选择(UDP 为 IPPROTO_UDP,TCP 为 IPPROTO_TCP)。

示例:创建 UDP Socket

int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
    perror("socket error"); // 打印错误信息
    exit(1);
}

2. bind() —— 绑定 IP 与端口

功能:将 Socket 描述符与本地 IP 地址、端口号绑定,让系统知道该 Socket 监听哪个端口的网络数据。

核心说明:

  • 服务端必须显式绑定:服务端的端口需要是'众所周知'的固定值,让客户端能准确发送数据,IP 推荐使用 INADDR_ANY(表示绑定本机所有网卡的 IP,接收来自任意网卡的数据)。
  • 客户端无需显式绑定:客户端会在首次调用 sendto() 时,由系统自动绑定一个随机端口和本机 IP,避免端口冲突。

函数原型:

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数说明:

  • sockfd:由 socket() 创建的 Socket 描述符;
  • addr:指向套接字地址结构的指针,UDP/TCP 使用 struct sockaddr_in(IPv4 专用),需强制转换为 struct sockaddr*;
  • addrlen:套接字地址结构的大小,sizeof(struct sockaddr_in)。

套接字地址结构(struct sockaddr_in):

struct sockaddr_in {
    sa_family_t sin_family; // 协议域,与 socket() 的 domain 一致,AF_INET
    in_port_t sin_port;     // 端口号,需转换为网络字节序(htons())
    struct in_addr sin_addr; // IP 地址结构
};

struct in_addr {
    in_addr_t s_addr; // IP 地址,需转换为网络字节序(inet_addr()/inet_pton())
};

示例:服务端绑定端口 8888,IP 为 INADDR_ANY

struct sockaddr_in local;
memset(&local, 0, sizeof(local)); // 初始化结构体,置 0
local.sin_family = AF_INET;
local.sin_port = htons(8888); // 主机字节序转网络字节序
local.sin_addr.s_addr = INADDR_ANY; // 绑定本机所有 IP
int ret = bind(sockfd, (struct sockaddr*)&local, sizeof(local));
if (ret < 0) {
    perror("bind error");
    exit(2);
}

3. sendto() —— 发送数据报

功能:向指定的目标 IP 和端口发送 UDP 数据报,是 UDP 编程的核心发送接口。

函数原型:

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);

参数说明:

  • sockfd:Socket 描述符
  • buf:指向要发送数据的缓冲区指针
  • len:要发送数据的字节数
  • flags:发送标志,填 0 表示默认(阻塞发送)
  • dest_addr:目标端的套接字地址结构(包含目标 IP 和端口)
  • addrlen:目标地址结构的大小,sizeof(struct sockaddr_in)。

返回值:成功返回发送的字节数,失败返回 -1。

示例:向服务端(192.168.1.100:8888)发送数据

std::string data = "hello udp";
struct sockaddr_in server;
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(8888);
server.sin_addr.s_addr = inet_addr("192.168.1.100"); // 点分十进制转网络字节序
ssize_t n = sendto(sockfd, data.c_str(), data.size(), 0, (struct sockaddr*)&server, sizeof(server));
if (n < 0) {
    perror("sendto error");
}

4. recvfrom() —— 接收数据报

功能:接收来自任意客户端的 UDP 数据报,并获取发送方的 IP 和端口号,是 UDP 编程的核心接收接口。

函数原型:

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);

参数说明:

  • sockfd:Socket 描述符
  • buf:指向接收数据的缓冲区指针
  • len:接收缓冲区的大小
  • flags:接收标志,填 0 表示默认(阻塞接收)
  • src_addr:输出参数,用于存储发送方的套接字地址结构(获取发送方 IP 和端口)
  • addrlen:输入输出参数,入参为 src_addr 的大小,出参为实际的地址结构大小。

返回值:成功返回接收的字节数,失败返回 -1,返回 0 表示连接关闭(UDP 几乎不会出现)。

示例:接收数据并获取发送方信息

char buffer[1024] = {0};
struct sockaddr_in peer; // 存储发送方信息
socklen_t len = sizeof(peer);
ssize_t m = recvfrom(sockfd, buffer, sizeof(buffer)-1, 0, (struct sockaddr*)&peer, &len);
if (m > 0) {
    buffer[m] = 0; // 手动添加字符串结束符
    // 获取发送方 IP 和端口(网络字节序转主机字节序)
    std::string peer_ip = inet_ntoa(peer.sin_addr);
    uint16_t peer_port = ntohs(peer.sin_port);
    std::cout << "[" << peer_ip << ":" << peer_port << "]# " << buffer << std::endl;
}

5. close() —— 关闭套接字

功能:关闭 Socket 描述符,释放系统分配的网络资源,与文件操作的 close() 一致。

函数原型:

int close(int sockfd);

示例:

close(sockfd); // 关闭后,sockfd 不可再使用

四、UDP Socket 编程基本流程

服务端流程(固定步骤)

  1. 调用 socket() 创建 UDP Socket 描述符
  2. 调用 bind() 绑定固定端口和 INADDR_ANY
  3. 循环调用 recvfrom() 接收客户端数据
  4. (可选)调用 sendto() 向客户端返回响应数据
  5. 通信结束后,调用 close() 关闭 Socket

客户端流程(固定步骤)

  1. 调用 socket() 创建 UDP Socket 描述符
  2. 填充服务端的 struct sockaddr_in 结构(IP + 端口)
  3. 调用 sendto() 向服务端发送数据(系统自动绑定随机端口)
  4. (可选)调用 recvfrom() 接收服务端响应
  5. 通信结束后,调用 close() 关闭 Socket

五、核心网络字节序转换接口

网络传输的数据采用大端序(网络字节序),而主机的字节序可能是大端或小端(x86 架构为小端),因此需要通过接口完成主机字节序与网络字节序的转换:

  1. htons(uint16_t n):主机字节序(16 位)转网络字节序,用于端口号转换
  2. ntohs(uint16_t n):网络字节序(16 位)转主机字节序,用于获取端口号
  3. inet_addr(const char *cp):点分十进制 IP 字符串转网络字节序 32 位整数,简单但有兼容性问题
  4. inet_pton(int family, const char *cp, void *addr):推荐使用,点分十进制 IP 字符串转网络字节序,支持 IPv4/IPv6
  5. inet_ntoa(struct in_addr in):网络字节序 IP 转点分十进制字符串,非线程安全
  6. inet_ntop(int family, const void *addr, char *cp, size_t len):推荐使用,网络字节序 IP 转点分十进制字符串,线程安全,支持 IPv4/IPv6

Socket 编程是网络编程的基础,而 UDP Socket 因无连接、开销小、实时性高的特点,成为轻量级网络通信的首选。核心需掌握 5 个接口:socket()(创建)、bind()(绑定)、sendto()(发送)、recvfrom()(接收)、close()(关闭),以及网络字节序与主机字节序的转换。

Python self 关键字详解:与 Java this 对比及方法类型区分
  • Python 微服务分布式追踪实战:基于 OpenTelemetry 的全链路监控
  • Python 文件路径详解:绝对路径、相对路径与 pathlib
  • Java 基础进阶:数据类型与面向对象
  • FastJson2 完整使用指南(Java 后端企业级实战)
  • Flutter 导航组件 TabBar、AppBar 等构建应用导航体系
  • VS Code Copilot Chat 扩展调试指南:快速解决运行问题
  • GitHub Copilot Token 消耗过快:5 种省流策略与模型替代方案
  • 数据结构:快速排序算法详解(双指针法)
  • AIGCJson 库源码解析:宏与模板实现的 JSON 序列化
  • LG WebOS 电视安装第三方应用指南
  • 基于 Kafka 的医嘱事件架构设计