一、预备知识
1.1 理解 IP 地址
在 IP 数据报头部中,有两个 IP 地址,分别叫做源 IP 地址,和目的 IP 地址。
Linux 网络编程涉及 IP 地址、端口号及套接字概念。TCP 为可靠面向流协议,UDP 为不可靠面向报文协议。网络字节序规定为大端模式。介绍 socket 编程常见 API,包括 socket、bind、listen、accept、connect 等函数,以及字节序转换(htonl 等)和 IP 地址转换(inet_aton 等)函数。此外还说明了 sockaddr 结构的作用。

在 IP 数据报头部中,有两个 IP 地址,分别叫做源 IP 地址,和目的 IP 地址。
思考:我们光有 IP 地址就可以完成通信了嘛? IP 地址能够标识互联网中的唯一的一台主机。想象一下发 qq 消息的例子,有了 IP 地址能够把消息发送到对方的机器上,但是还需要有一个其他的标识来区分出,这个数据要给哪个程序进行解析。
两台主机间通信并不是使用机器通信,而是使用机器上的程序进行通信,程序也就是进程,所以需要一个标识来标记主机中的进程,也就是这里所讲的端口号,端口号(port)是传输层协议的内容,能够标识主机中唯一的一个进程。
传输层协议(TCP 和 UDP)的数据段中有两个端口号,分别叫做源端口号和目的端口号,就是在描述'数据是谁发的,要发给谁'。
IP 地址能够标识互联网中的唯一的一台主机,端口号能够标识主机中唯一的一个进程。也就是说{IP 地址,port},就能够标识网络中唯一的一个进程,使用网络进行通信的本质就是使用{IP 地址,port}进行通信的,它的名字叫做网络套接字。
我们之前在学习系统编程的时候,学习了 PID 用来表示唯一一个进程;此处我们的端口号也是唯一表示一个进程。那么这两者之间是怎样的关系?
PID 是用来标识主机上的进程的,port 是用来标识主机上用来进行网络通信的进程的。由于主机上并不是所有进程都需要进行网络通信的,并且我们希望其他模块(进程模块)与网络模块进行解耦,所以就有了端口号的概念。
一个端口号通常与一个进程进行绑定,一个进程也可以绑定多个端口号,但是一个端口号不能被多个进程绑定。
此处我们先对TCP(Transmission Control Protocol 传输控制协议)和UDP(User Datagram Protocol 用户数据报协议)有一个直观的认识,后面我们再详细讨论 TCP 和 UDP 的一些细节问题。大家不要被两个协议特点所迷惑,这两个协议只有不同,没有好坏。
TCP 协议的特点
UDP 协议的特点
我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分,磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分,网络数据流同样有大端小端之分。那么如何定义网络数据流的地址呢?
// 头文件
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);
功能:创建一个新的套接字。
参数:
返回值:成功时返回套接字文件描述符,失败时返回 -1 并设置 errno。
// 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr* address, socklen_t address_len);
功能:将套接字与特定的 IP 地址和端口号绑定。
参数:
返回值:成功时返回 0,失败时返回 -1 并设置 errno。
// 开始监听 socket (TCP, 服务器)
int listen(int socket, int backlog);
功能:使套接字进入监听状态,准备接受连接请求。
参数:
返回值:成功时返回 0,失败时返回 -1 并设置 errno。
// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address, socklen_t* address_len);
功能:接受一个连接请求。
参数:
返回值:成功时返回新的套接字文件描述符用于与客户端通信,失败时返回 -1 并设置 errno。
// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr* addr, socklen_t addrlen);
功能:主动与服务器建立连接。
参数:
返回值:成功时返回 0,失败时返回 -1 并设置 errno。
// 头文件
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
功能:将 32 位无符号整数从主机字节序转换为网络字节序。
参数:
返回值:返回转换后的以网络字节序表示的 32 位无符号整数。
uint32_t ntohl(uint32_t netlong);
功能:将 32 位无符号整数从网络字节序转换回主机字节序。
参数:
返回值:返回转换后的以主机字节序表示的 32 位无符号整数。
uint16_t htons(uint16_t hostshort);
功能:将 16 位无符号整数从主机字节序转换为网络字节序。
参数:
返回值:返回转换后的以网络字节序表示的 16 位无符号整数。
uint16_t ntohs(uint16_t netshort);
功能:将 16 位无符号整数从网络字节序转换回主机字节序。
参数:
返回值:返回转换后的以主机字节序表示的 16 位无符号整数。
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int inet_aton(const char* cp, struct in_addr* inp);
功能:将点分十进制的 IPv4 地址字符串转换为网络字节序的二进制形式。
参数:
返回值:
in_addr_t inet_addr(const char* cp);
功能:将点分十进制字符串形式的 IP 地址转换为 32 位二进制整数形式(网络字节序)。
参数:
返回值:如果转换成功,返回转换后的 32 位二进制整数;如果转换失败,返回 INADDR_NONE(通常为 0xffffffff)。不过需要注意的是,INADDR_NONE 也是一个有效的 IP 地址(255.255.255.255),这可能会导致一些混淆,因此更推荐使用 inet_aton 函数。
in_addr_t inet_network(const char* cp);
功能:将点分十进制字符串形式的 IP 地址转换为 32 位二进制整数形式(主机字节序),并且通常用于提取网络号。
参数:
返回值:如果转换成功,返回转换后的 32 位二进制整数;如果转换失败,返回 -1。
char* inet_ntoa(struct in_addr in);
功能:将网络字节序的 IPv4 地址(struct in_addr)转换回点分十进制的字符串形式。
参数:
返回值:返回一个指向静态分配的、以 null 结尾的字符串的指针,该字符串包含转换后的点分十进制 IPv4 地址。注意,返回的字符串指针指向一个静态分配的区域,因此每次调用 inet_ntoa 时,上次调用返回的字符串可能会被覆盖。
ssize_t recvfrom(int sockfd, void* buf, size_t len, int flags, struct sockaddr* src_addr, socklen_t *addrlen);
功能:从指定的套接字接收数据报,并可选地获取发送方的地址信息。
参数:
返回值:
ssize_t sendto(int sockfd, const void* buf, size_t len, int flags, const struct sockaddr* dest_addr, socklen_t addrlen);
功能:用于向指定的地址发送数据报。
参数:
返回值:
网络编程中,socket 分为很多种类:
由于设计者想用同一套接口就解决上面应用场景,所以就设计出来 sockaddr_in 结构体类型,通过下图我们可以看到 sockaddr_in 结构体与 sockaddr_un 结构体都有一个地址类型,只要取得某种 sockaddr 结构体的首地址,不需要知道具体是哪种类型的 sockaddr 结构体,就可以根据地址类型字段确定结构体中的内容。


微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online