news 2026/3/27 22:45:25

【Linux网络编程】Socket编程入门前必须搞懂的核心概念

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【Linux网络编程】Socket编程入门前必须搞懂的核心概念

前言:我们有了IP定位到对应的主机的概念后,信息传递到对应的主机后,而主机中有那么多的进程,该怎么知道把信息交给主机中的哪个进程呢?

一、端口号

IP 到 端口号:如何精准定位

我们在网络层通过 IP 地址找到了目标主机,但这并不是终点。

传输的真正目的:数据并不是要发给“主机”这个铁壳子,而是发给正在运行的人使用的程序(比如你正在用的微信、浏览器)。

进程的代表:在操作系统中,人通过启动进程来完成任务。所以,数据传输的最终目的地是主机内部的某个特定进程

端口号 (Port) 的作用

既然已经到了目标主机,系统中有那么多进程,怎么知道数据该给谁?这就需要端口号

  • 定义:端口号是一个2字节 (16位)的整数 。
  • 功能:用来标识主机上唯一的一个网络进程 。
  • 绑定规则:一个端口号只能被一个进程占用,但一个进程可以绑定多个端口号 。

端口号范围划分

  • 0 - 1023 (知名端口):HTTP (80), FTP (21), SSH (22) 等级协议专用的,我们自己写程序尽量别碰 。
  • 1023 - 65535 (动态端口)操作系统动态分配的,或者我们自己写服务器时绑定的,就在这儿挑 。

思考:为什么不用 PID (进程ID)?

PID 是系统层面的唯一标识,确实也能找到进程。但如果网络协议直接绑定 PID,一旦操作系统调整了 PID 的分配策略,网络协议就得跟着改。使用端口号可以将网络管理系统进程管理解耦 。

二、什么是 Socket?

搞懂了 IP 和 端口号,Socket 的概念就水到渠成了。

  • Socket (套接字):本质就是IP地址 + 端口号
  • 唯一性IP标识了全网唯一的主机Port标识了该主机上唯一的进程。所以IP + Port就能标识互联网中独一无二的一个进程
  • 通信本质:网络通信的本质,其实就是两个互联网进程之间的 IPC (进程间通信)

三、传输层协议初识:TCP vs UDP

在写 Socket 代码前,得先选好用哪种协议。Linux 内核在传输层主要提供了两种选择:

特性TCP (传输控制协议)UDP (用户数据报协议)
连接性

有连接(打电话,先接通)

无连接(发短信,直接发)

可靠性

可靠传输(保证数据送达)

不可靠传输(丢了不管)

数据形式

面向字节流

面向数据报

注:详细的 TCP/UDP 机制后续会有专门章节,目前只需知道这些区别即可 。

三、 网络字节序

我们都知道内存里的数据有大端和小端之分。

  • 大端:高位字节存放在低地址。

  • 小端:低位字节存放在低地址(我们常用的 x86 架构大多是小端)。

为什么网络编程要注意这个?

这就好比两个不同方言的人说话。如果发送端主机是小端机,它把一个 32 位的整数(比如 IP 地址)按内存地址从低到高发出去;而接收端可能是大端机,或者网络协议规定了不同的读法,那数据就全乱套了。

为了解决这个问题,TCP/IP 协议强行规定:网络数据流应采用大端字节序(即低地址高字节)

这意味着:

  • 不管你的主机是大端还是小端,发数据前,必须把数据转成大端(网络字节序)。
  • 收数据后,必须把数据从大端转回主机字节序。

我们可用举个例子,假设我们要发一个0x1234abcd

发送端通常将发送缓冲区的数据按内存地址从低到高发出,网络流规定:先发出的数据认为是高位。

如果是小端机,内存里存的是cd ab 34 12(低位在低地址)。如果不转换直接发,网络那边读出来的就是0xcdab3412,这就错了。

转换函数

Linux 提供了<arpa/inet.h>库函数来做转换。为了代码的可移植性,写网络程序必须调用这些函数,不要自己手写位移操作。

这些函数名非常好记:h代表 host(主机),n代表 network(网络),s代表 short(16位),l代表 long(32位)。

  • 发送时(Host to Network):
#include <arpa/inet.h> // 用来转换32位 uint32_t htonl(uint32_t hostlong); // 用来转换16位 uint16_t htons(uint16_t hostshort);

如果主机本身就是大端,这些函数什么都不做,直接返回原值 ;如果是小端,它会自动帮你翻转

  • 接收时(Network to Host):
uint32_t ntohl(uint32_t netlong); uint16_t ntohs(uint16_t netshort);

四、Socket 编程接口 (Socket API)

Socket API 是系统调用,属于 OS 内核提供的功能。所有的网络功能,必须通过系统调用来实现

常见 API 一览

写 TCP 服务器/客户端的“五板斧”:

1. socket:创建套接字(相当于买个手机)

// domain: 协议族 (AF_INET 用IPv4) // type: 服务类型 (SOCK_STREAM 用TCP, SOCK_DGRAM 用UDP) int socket(int domain, int type, int protocol);

2. bind:绑定端口和IP(相当于给手机插卡,固定号码)

// 这里的 struct sockaddr* 是个通用指针 int bind(int socket, const struct sockaddr *address, socklen_t address_len);

3. listen:监听(TCP服务器专用,相当于设置手机响铃模式)

int listen(int socket, int backlog);

4. accept:接收连接(TCP服务器专用,相当于有人打进来了,你按接听)

int accept(int socket, struct sockaddr *address, socklen_t* address_len);

5. connect:发起连接(TCP客户端专用,相当于拨号)。

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

在看bindconnect的函数原型时,你会发现参数类型都是struct sockaddr *

但实际上我们在写 IPv4 程序时,定义的却是struct sockaddr_in。这是为什么?

sockaddr(通用结构体)

Socket API 是一层抽象接口,它不仅支持 IPv4,还支持 IPv6、UNIX Domain Socket 等各种协议 。 为了能让bind等函数接收各种协议的地址,OS 定义了一个通用的结构体:

struct sockaddr { unsigned short sa_family; // 16位地址类型 (AF_INET, AF_UNIX...) char sa_data[14]; // 14字节的地址数据 };

这个结构体很难用,因为它的 IP 和 Port 是混在一起存在sa_data里的。

sockaddr_in(IPv4 专用结构体)

而为了方便操作,OS使用专门针对 IPv4 设计的结构体 :

struct sockaddr_in { short int sin_family; // 地址族 unsigned short int sin_port; // 16位端口号 struct in_addr sin_addr; // 32位IP地 unsigned char sin_zero[8]; // 8字节填充,为了和 struct sockaddr 大小保持一致 };

注意struct in_addr里面其实就是一个uint32_t s_addr,用来存 32 位的 IP 地址 。

内存模型与强制类型转换

虽然上述两种结构体定义不同,但它们的大小是一样的,而且前 16 位(2字节)都是family字段。

只要取得了结构体的首地址,OS 就可以根据前 16 位的family字段判断这是 IPv4 还是 IPv6 。我们在代码中定义sockaddr_in进行赋值,然后在调用 API 时,强制类型转换struct sockaddr *

实际代码使用示例:

#include <netinet/in.h> #include <arpa/inet.h> struct sockaddr_in local; // 1. 清空结构体 (有的系统会有垃圾值) bzero(&local, sizeof(local)); // 2. 填充协议族 local.sin_family = AF_INET; // IPv4 // 3. 填充端口号 (注意字节序转换!) local.sin_port = htons(8080); // 4. 填充IP地址 (INADDR_ANY 表示绑定本机所有网卡) // htonl转换IP,虽然 INADDR_ANY 是0,转不转都一样,但好习惯要养成 local.sin_addr.s_addr = htonl(INADDR_ANY); // 5. 强转传参 bind(sockfd, (struct sockaddr*)&local, sizeof(local));
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/21 3:22:46

GPT-2 Large本地部署实战手册:从零到精通的无GPU推理指南

GPT-2 Large本地部署实战手册&#xff1a;从零到精通的无GPU推理指南 【免费下载链接】gpt2-large 项目地址: https://ai.gitcode.com/hf_mirrors/openai-community/gpt2-large 还在为高昂的API费用和隐私安全问题困扰吗&#xff1f;今天我们一起来探索如何在本地环境高…

作者头像 李华
网站建设 2026/3/26 20:56:07

免费商用字体终极指南:霞鹜文楷完整教程

免费商用字体终极指南&#xff1a;霞鹜文楷完整教程 【免费下载链接】LxgwWenKai LxgwWenKai: 这是一个开源的中文字体项目&#xff0c;提供了多种版本的字体文件&#xff0c;适用于不同的使用场景&#xff0c;包括屏幕阅读、轻便版、GB规范字形和TC旧字形版。 项目地址: htt…

作者头像 李华
网站建设 2026/3/26 11:10:54

Wan2.2-T2V-A14B在智能座舱车载娱乐内容生成中的延时测试

Wan2.2-T2V-A14B在智能座舱车载娱乐内容生成中的延时测试 智能座舱的“内容革命”&#xff1a;从播放到创造 当一辆新能源汽车驶入高速服务区&#xff0c;后排的孩子突然说&#xff1a;“我想看一只会飞的恐龙穿越火山&#xff01;”——在过去&#xff0c;这只能靠预存动画片…

作者头像 李华
网站建设 2026/3/26 13:32:13

Markdown Here终极指南:轻松实现邮件格式转换

Markdown Here终极指南&#xff1a;轻松实现邮件格式转换 【免费下载链接】markdown-here Google Chrome, Firefox, and Thunderbird extension that lets you write email in Markdown and render it before sending. 项目地址: https://gitcode.com/gh_mirrors/ma/markdown…

作者头像 李华
网站建设 2026/3/27 18:12:03

轻量级HTTP服务器终极指南:从入门到精通

轻量级HTTP服务器终极指南&#xff1a;从入门到精通 【免费下载链接】httpserver.h httpserver.h - 一个单头文件C库&#xff0c;用于构建事件驱动的非阻塞HTTP服务器。 项目地址: https://gitcode.com/gh_mirrors/ht/httpserver.h 本文为您全面解析轻量级HTTP服务器的实…

作者头像 李华
网站建设 2026/3/24 20:40:41

Qwen2-VL-Finetune:阿里云视觉语言模型高效微调完全指南

Qwen2-VL-Finetune是一个专为阿里云Qwen2-VL、Qwen2.5-VL和Qwen3-VL系列视觉语言模型设计的开源微调框架。该项目基于HuggingFace和Liger-Kernel构建&#xff0c;支持全量微调、LoRA/QLoRA、DPO、GRPO等多种训练策略&#xff0c;让开发者能够在有限的计算资源下高效完成视觉语言…

作者头像 李华