Linux:了解Socket编程
1.理解源IP地址和目的IP地址
IP 在网络中,⽤来标识主机的唯⼀性
源IP地址:就是寄信人的地址。它告诉网络:“这个数据包是从哪里发出的”。
目的IP地址:就是收信人的地址。它告诉网络:“这个数据包要去往哪里”。
特性 | 源IP地址 | 目的IP地址 |
---|---|---|
角色 | 发送方地址 | 接收方地址 |
作用 | 告诉接收方“谁”发的,以便对方能回复 | 告诉网络“这个数据包要去哪里” |
类比 | 信封上的寄件人地址 | 信封上的收件人地址 |
可变性 | 在一次完整的通信中,请求和回复的源和目的是互换的。 |
但是这⾥要思考⼀个问题,数据传输到主机是目的吗?数据传输到主机不是目的,而是手段。到达主机内部,在交给主机内的进程,才是目的。

2.认识端口号
端口号( port )是传输层协议的内容.
- 端⼝号是⼀个 2 字节 16 位的整数;
- 端⼝号⽤来标识⼀个进程, 告诉操作系统, 当前的这个数据要交给哪⼀个进程来处理;
- IP地址 + 端⼝号能够标识⽹络上的某⼀台主机的某⼀个进程;
- ⼀个端⼝号只能被⼀个进程占⽤.
端口号范围划分
0 - 1023 : 知名端⼝号, HTTP, FTP, SSH 等这些⼴为使⽤的应⽤层协议, 他们的端⼝号都是固定的1024 - 65535 : 操作系统动态分配的端⼝号. 客户端程序的端⼝号, 就是由操作系统从这个范围分配的.
理解 "端口号" 和 "进程ID"
pid 表示唯一个进程; 此处我们的端口号也是唯⼀表示⼀个进程. 那么这两者之间是怎样的关系?
⼀个进程可以绑定多个端⼝号; 但是⼀个端⼝号不能被多个进程绑定;避免强耦合
理解源端口号和目的端口号
传输层协议( TCP 和 UDP )的数据段中有两个端口号, 分别叫做源端口号和目的端口号. 就是在描述 "数据是谁发的, 要发给谁";
理解socket
- 综上, IP 地址⽤来标识互联⽹中唯⼀的⼀台主机, port ⽤来标识该主机上唯⼀的⼀个网络进程IP+Port 就能表⽰互联⽹中唯⼀的⼀个进程
- 所以,通信的时候,本质是两个互联⽹进程代表⼈来进⾏通信,{srcIp,srcPort,dstIp,dstPort} 这样的4元组就能标识互联⽹中唯⼆的两个进程
- 所以,网络通信的本质,也是进程间通信
- 我们把 ip+port 叫做套接字 socket
3.传输层的典型代表
如果我们了解了系统,也了解了网络协议栈,我们就会清楚,传输层是属于内核的,那么我们要通
过网络协议栈进行通信,必定调用的是传输层提供的系统调用,来进行的网络通信。
认识TCP协议
此处我们先对 TCP ( Transmission Control Protocol 传输控制协议)有⼀个简单的认识
- 传输层协议
- 有连接
- 可靠传输
- 面向字节流
认识UDP协议
此处我们也是对 UDP ( User Datagram Protocol ⽤户数据报协议)有⼀个简单的认识
- 传输层协议
- 无连接
- 不可靠传输
- 面向数据报
4.网络字节序
我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分, ⽹络数据流同样有大端小端之分. 那么如何定义网络数据流的地址呢?
- 发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出;
- 接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到⾼的顺序保存;
- 因此,网络数据流的地址应这样规定: 先发出的数据是低地址,后发出的数据是⾼地址.
- TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节
- 不管这台主机是大端机还是小端机, 都会按照这个TCP/IP规定的网络字节序来发送/接收数据;
- 如果当前发送主机是小端, 就需要先将数据转成大端; 否则就忽略, 直接发送即可;
小小小——低地址,低地址,小端
为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换。
htons()(Host TO Network Short):将 16位整数(short)从 主机字节序 转换为 网络字节序(大端序)。
ntohs()(Network TO Host Short):将 16位整数(short)
从 网络字节序 转换回 主机字节序。uint16_t host_port = 8080; // 主机字节序(可能是小端序)
uint16_t net_port = htons(host_port); // 转换为网络字节序(大端序)uint16_t original_port = ntohs(net_port); // 转换回主机字节序inet_pton()(Presentation TO Network):将 IP地址字符串(如 "127.0.0.1")
转换为 二进制格式(struct in_addr)。
inet_ntop()(Network TO Presentation):将 二进制格式的IP地址 转换回 字符串格式。// 1. 字符串 -> 二进制(inet_pton)
const char *ip_str = "192.168.1.1";struct in_addr ip_bin;if (inet_pton(AF_INET, ip_str, &ip_bin) != 1) {perror("inet_pton failed");return 1;} // 2. 二进制 -> 字符串(inet_ntop)char ip_str_back[INET_ADDRSTRLEN]; // INET_ADDRSTRLEN = 16(IPv4)if (inet_ntop(AF_INET, &ip_bin, ip_str_back, INET_ADDRSTRLEN) == NULL) {perror("inet_ntop failed");return 1;}所有发送到网络上的数据,都必须是大端的
5.socket编程接口
// 创建 socket ⽂件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);// 绑定端⼝号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *address, socklen_t address_len);// 开始监听socket (TCP, 服务器)
int listen(int socket, int backlog);// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address, socklen_t* address_len);// 建⽴连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);