在C语言中,套接字(Socket)编程主要用于网络通信,尤其是在基于TCP/IP协议的应用程序开发中。常用的套接字编程API主要基于Berkeley Sockets(伯克利套接字)接口,这些函数通常在<sys/socket.h>和<netinet/in.h>头文件中定义。以下是对常见套接字API的详细讲解,包括函数功能、参数、返回值、涉及的结构体及其成员的含义。
1. socket()
功能
创建新的套接字。
函数原型
int socket(int domain, int type, int protocol);
参数
domain: 指定通信协议族(协议域)。- 类型:
int - 常见值:
AF_INET(IPv4协议)AF_INET6(IPv6协议)AF_UNIX(本地通信)
- 含义: 定义套接字的地址格式和通信范围。
- 类型:
type: 指定套接字类型。- 类型:
int - 常见值:
SOCK_STREAM(面向连接的TCP流)SOCK_DGRAM(无连接的UDP数据报)SOCK_RAW(原始套接字)
- 含义: 定义通信的语义。
- 类型:
protocol: 指定具体协议。- 类型:
int - 常见值:
- 通常为
0(表示由domain和type自动选择默认协议,如TCP或UDP) - 特殊值(如
IPPROTO_TCP、IPPROTO_UDP)用于显式指定协议。
- 通常为
- 含义: 细化协议选择。
- 类型:
返回值
- 类型:
int - 含义:
- 成功: 返回套接字文件描述符(非负整数)。
- 失败: 返回
-1,并设置errno表示错误。
相关结构体
无直接结构体参数。
2. bind()
功能
将套接字绑定到特定的地址和端口。
函数原型
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数
sockfd: 要绑定的套接字文件描述符。- 类型:
int - 含义: 由
socket()创建的套接字。
- 类型:
addr: 指向地址结构体的指针。- 类型:
const struct sockaddr * - 含义: 指定绑定的地址和端口。
- 类型:
addrlen: 地址结构体的大小。- 类型:
socklen_t(通常是unsigned int) - 含义:
addr指向的结构体长度。
- 类型:
返回值
- 类型:
int - 含义:
- 成功: 返回
0。 - 失败: 返回
-1,并设置errno。
- 成功: 返回
相关结构体
struct sockaddr- 定义:
struct sockaddr {sa_family_t sa_family; // 地址族char sa_data[14]; // 地址数据(具体含义依赖地址族) }; - 成员:
sa_family: 地址族(如AF_INET)。- 类型:
sa_family_t(通常是unsigned short) - 含义: 指定地址类型。
- 类型:
sa_data: 地址数据的字节数组。- 类型:
char[14] - 含义: 存储具体地址信息,但通常不直接使用。
- 类型:
- 定义:
- 实际常用:
struct sockaddr_in(针对IPv4)- 定义:
struct sockaddr_in {sa_family_t sin_family; // 地址族in_port_t sin_port; // 端口号struct in_addr sin_addr; // IP地址unsigned char sin_zero[8]; // 填充字节 }; - 成员:
sin_family: 地址族。- 类型:
sa_family_t - 含义: 通常为
AF_INET。
- 类型:
sin_port: 端口号。- 类型:
in_port_t(通常是uint16_t) - 含义: 网络字节序的端口号(如
htons(8080))。
- 类型:
sin_addr: IP地址。- 类型:
struct in_addr - 定义:
struct in_addr {in_addr_t s_addr; // IPv4地址(32位) }; - 成员:
s_addr: IPv4地址。- 类型:
in_addr_t(通常是uint32_t) - 含义: 网络字节序的IP地址(如
inet_addr("127.0.0.1"))。
- 类型:
- 类型:
sin_zero: 填充字节。- 类型:
unsigned char[8] - 含义: 用于对齐,通常置为
0。
- 类型:
- 定义:
3. listen()
功能
将套接字设置为监听状态,用于接受客户端连接(仅限TCP)。
函数原型
int listen(int sockfd, int backlog);
参数
sockfd: 要监听的套接字文件描述符。- 类型:
int - 含义: 已绑定的服务器套接字。
- 类型:
backlog: 等待连接队列的最大长度。- 类型:
int - 含义: 指定未完成连接的最大排队数(如
5或10)。
- 类型:
返回值
- 类型:
int - 含义:
- 成功: 返回
0。 - 失败: 返回
-1,并设置errno。
- 成功: 返回
相关结构体
无直接结构体参数。
4. accept()
功能
接受客户端连接请求,返回新的套接字用于通信(仅限TCP)。
函数原型
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数
sockfd: 监听的套接字文件描述符。- 类型:
int - 含义: 已调用
listen()的服务器套接字。
- 类型:
addr: 客户端地址信息。- 类型:
struct sockaddr * - 含义: 用于存储连接的客户端地址(通常转换为
struct sockaddr_in)。
- 类型:
addrlen: 地址结构体的长度。- 类型:
socklen_t * - 含义: 传入时为
addr的大小,函数返回时为实际地址长度。
- 类型:
返回值
- 类型:
int - 含义:
- 成功: 返回新的套接字文件描述符,用于与客户端通信。
- 失败: 返回
-1,并设置errno。
相关结构体
- 同
bind()中的struct sockaddr和struct sockaddr_in。
5. connect()
功能
发起与服务器的连接(用于客户端)。
函数原型
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数
sockfd: 客户端套接字文件描述符。- 类型:
int - 含义: 由
socket()创建的套接字。
- 类型:
addr: 目标服务器地址。- 类型:
const struct sockaddr * - 含义: 指定服务器的地址和端口。
- 类型:
addrlen: 地址结构体的长度。- 类型:
socklen_t - 含义:
addr的大小。
- 类型:
返回值
- 类型:
int - 含义:
- 成功: 返回
0。 - 失败: 返回
-1,并设置errno。
- 成功: 返回
相关结构体
- 同
bind()中的struct sockaddr和struct sockaddr_in。
6. send() 和 recv()
功能
send(): 发送数据。recv(): 接收数据。
函数原型
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
参数
sockfd: 套接字文件描述符。- 类型:
int - 含义: 已连接的套接字。
- 类型:
buf: 数据缓冲区。- 类型:
const void *(send)或void *(recv) - 含义: 发送或接收的数据存储位置。
- 类型:
len: 数据长度。- 类型:
size_t - 含义: 要发送或接收的字节数。
- 类型:
flags: 操作标志。- 类型:
int - 常见值:
0(默认行为)MSG_DONTWAIT(非阻塞)
- 含义: 修改发送/接收行为。
- 类型:
返回值
- 类型:
ssize_t - 含义:
- 成功: 返回实际发送/接收的字节数。
- 失败: 返回
-1,并设置errno。
相关结构体
无直接结构体参数。
7. close()
功能
关闭套接字。
函数原型
int close(int sockfd);
参数
sockfd: 要关闭的套接字文件描述符。- 类型:
int - 含义: 由
socket()或accept()返回的描述符。
- 类型:
返回值
- 类型:
int - 含义:
- 成功: 返回
0。 - 失败: 返回
-1,并设置errno。
- 成功: 返回
相关结构体
无直接结构体参数。
总结
以下是常用套接字API的快速参考表:
| 函数 | 功能 | 返回值类型 | 主要结构体 |
|---|---|---|---|
socket() | 创建套接字 | int | 无 |
bind() | 绑定地址 | int | sockaddr, sockaddr_in |
listen() | 开始监听 | int | 无 |
accept() | 接受连接 | int | sockaddr, sockaddr_in |
connect() | 发起连接 | int | sockaddr, sockaddr_in |
send() | 发送数据 | ssize_t | 无 |
recv() | 接收数据 | ssize_t | 无 |
close() | 关闭套接字 | int | 无 |
这些API是C语言网络编程的核心,配合结构体(如struct sockaddr_in)使用,可以实现基本的客户端-服务器通信。需要注意网络字节序(htons, ntohs, htonl, ntohl)和错误处理(errno)的使用。