在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
)的使用。