一、C 语言网络编程基础
(一)套接字概念与特点
介绍套接字是网络通信中的端点,具有跨进程、跨网络、双向通信、协议无关性和地址绑定等特点。
套接字作为网络通信的端点,实现了不同进程之间的数据交换,无论这些进程是在同一台机器上还是分布在不同的网络位置。跨进程通信使得不同的程序能够协同工作,共同完成复杂的任务。跨网络通信则打破了物理位置的限制,只要网络可达,不同地点的进程就可以进行通信。双向通信意味着套接字既可以发送数据,也可以接收数据,为交互性的应用提供了基础。协议无关性使得套接字可以支持多种网络协议,不仅仅局限于特定的一种,增加了其灵活性和适用性。而地址绑定则为每个套接字分配了唯一的地址,包括 IP 地址和端口号,确保数据能够准确地发送到目标套接字。
(二)头文件 <sys/socket.h> 概述
1.数据类型:socklen_t、sockaddr 等结构体的作用和意义。
- socklen_t 是一种无符号整型,通常用于表示与套接字相关的参数大小,如地址长度等,确保了跨平台的兼容性。在不同的操作系统中,对于地址长度等参数的表示可能会有所不同,socklen_t 的使用可以避免这种差异带来的问题。
- sockaddr 是一个通用的套接字地址结构,它被设计为一个抽象层,允许应用程序通过同一接口处理不同类型的网络协议和地址族。sockaddr 通常与更具体的结构体如 sockaddr_in(用于 IPv4)和 sockaddr_in6(用于 IPv6)结合使用。这些具体的结构体包含了特定协议所需的地址信息,如 IP 地址和端口号等。
2.常量:AF_INET、SOCK_STREAM 等常量的含义及用途。
- AF_INET 是地址族常量,标识 IPv4 协议。在网络编程中,当我们使用 AF_INET 时,意味着我们将使用 IPv4 地址进行通信。IPv4 地址由四个字节组成,通常以点分十进制形式表示,如 192.168.1.1。
- SOCK_STREAM 是套接字类型常量,对应 TCP(面向连接的流套接字)。使用 SOCK_STREAM 类型的套接字可以实现可靠的数据传输,数据按序到达,不会出现丢失、重复或乱序的情况。这种类型的套接字适用于对数据传输可靠性要求较高的应用,如文件传输、电子邮件等。
3.函数:socket、bind、listen 等函数的功能和参数解析。
- socket 函数用于创建一个新的套接字,它的原型为 int socket(int domain, int type, int protocol)。其中,domain 参数指定通信域(地址族),如 AF_INET(IPv4)或 AF_INET6(IPv6);type 参数指定套接字类型,如 SOCK_STREAM(TCP)或 SOCK_DGRAM(UDP);protocol 参数指定使用的协议,一般设置为 0,让系统自动选择与 domain 和 type 匹配的默认协议。如果成功创建套接字,返回一个非负整数,即套接字描述符,用于后续的套接字操作;如果失败,返回 -1,并设置全局变量 errno 为相应的错误代码。
- bind 函数将一个套接字与本地地址(IP 地址和端口号)绑定,使得该套接字可以接收发往该地址的连接请求或数据报。它的原型为 int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)。sockfd 是由 socket 函数返回的套接字描述符,addr 是一个指向包含本地地址信息的 sockaddr 结构体的指针,addrlen 是 addr 所指向的结构体的长度。
- listen 函数使一个 TCP 套接字进入被动监听状态,等待客户端的连接请求。它的原型为 int listen(int sockfd, int backlog)。sockfd 是要监听的套接字描述符,backlog 参数指定同时可接纳的最大连接请求队列长度。
二、TCP 通信实现
(一)服务器端流程
1.创建套接字:socket 函数参数及返回值解析。
- socket函数用于创建一个新的套接字,其原型为int socket(int domain, int type, int protocol)。其中,domain参数指定通信域,通常使用AF_INET表示 IPv4 地址族。type参数指定套接字类型,对于 TCP 通信,使用SOCK_STREAM表示面向连接的流套接字。protocol参数指定使用的协议,一般设置为 0,让系统自动选择与domain和type匹配的默认协议,通常为IPPROTO_TCP。如果成功创建套接字,返回一个非负整数,即套接字描述符,用于后续的套接字操作;如果失败,返回 -1,并设置全局变量errno为相应的错误代码。
2.绑定地址:sockaddr_in 结构体与 bind 函数的使用。
- sockaddr_in结构体用于存储 IPv4 地址和端口号等信息。其成员包括sin_family(通常设置为AF_INET)、sin_port(存储端口号,需使用htons函数将主机字节序转换为网络字节序)、sin_addr(存储 IP 地址,可使用inet_addr函数将点分十进制形式的 IP 地址转换为整数形式)和sin_zero(一般用 0 填充,确保结构体大小与sockaddr结构体一致)。bind函数将一个套接字与本地地址(IP 地址和端口号)绑定,其原型为int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)。sockfd是由socket函数返回的套接字描述符,addr是一个指向sockaddr_in结构体的指针,需强制转换为const struct sockaddr *类型&