Socket API 核心函数详解
Socket API 核心函数详解
一、TCP 核心函数
1. socket()
- 创建套接字
c
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
- 功能:创建一个套接字描述符,用于后续网络通信。
- 参数:
domain
:协议族(如AF_INET
表示 IPv4,AF_INET6
表示 IPv6)。type
:套接字类型(如SOCK_STREAM
表示 TCP,SOCK_DGRAM
表示 UDP)。protocol
:通常为 0,表示自动选择对应类型的默认协议。
- 返回值:成功返回套接字描述符(非负整数),失败返回
-1
。 - 示例:
c
int sockfd = socket(AF_INET, SOCK_STREAM, 0); // 创建TCP套接字
2. bind()
- 绑定地址和端口
c
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
- 功能:将套接字与指定的 IP 地址和端口号绑定。
- 参数:
sockfd
:socket()
返回的套接字描述符。addr
:指向struct sockaddr
的指针,包含 IP 地址和端口信息。addrlen
:地址结构的长度。
- 返回值:成功返回 0,失败返回
-1
。 - 示例:
c
struct sockaddr_in server_addr; server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; // 绑定所有可用接口 server_addr.sin_port = htons(8888); // 端口号需转换为网络字节序 bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
3. listen()
- 监听连接
c
#include <sys/socket.h>
int listen(int sockfd, int backlog);
- 功能:将套接字设置为被动模式(监听模式),等待客户端连接。
- 参数:
sockfd
:套接字描述符。backlog
:允许的最大连接请求队列长度(如SOMAXCONN
表示系统默认值)。
- 返回值:成功返回 0,失败返回
-1
。 - 示例:
c
listen(sockfd, SOMAXCONN); // 监听客户端连接
4. accept()
- 接受连接
c
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
- 功能:从等待连接队列中取出一个连接请求,创建新的套接字用于与客户端通信。
- 参数:
sockfd
:监听套接字描述符。addr
:存储客户端地址信息的结构体指针(可设为NULL
)。addrlen
:地址结构长度的指针。
- 返回值:成功返回新的客户端套接字描述符,失败返回
-1
。 - 示例:
c
struct sockaddr_in client_addr; socklen_t client_addr_len = sizeof(client_addr); int connfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_addr_len); // connfd 用于与客户端通信
5. connect()
- 建立连接(客户端)
c
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
- 功能:客户端向服务器发起连接请求。
- 参数:
sockfd
:客户端套接字描述符。addr
:服务器地址信息结构体指针。addrlen
:地址结构长度。
- 返回值:成功返回 0,失败返回
-1
。 - 示例:
c
struct sockaddr_in server_addr; server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 服务器IP server_addr.sin_port = htons(8888); // 服务器端口 connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
6. send()
/recv()
- 发送 / 接收数据
c
#include <sys/socket.h>
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
:套接字描述符。buf
:发送 / 接收数据的缓冲区。len
:数据长度。flags
:通常为 0,或设置特殊标志(如MSG_DONTWAIT
表示非阻塞)。
- 返回值:
send()
:成功返回实际发送的字节数,失败返回-1
。recv()
:返回接收到的字节数,连接关闭返回 0,失败返回-1
。
- 示例:
c
// 发送数据 char *msg = "Hello, server!"; send(sockfd, msg, strlen(msg), 0);// 接收数据 char buffer[1024]; int n = recv(sockfd, buffer, sizeof(buffer), 0); if (n > 0) buffer[n] = '\0'; // 确保字符串以'\0'结尾
二、UDP 核心函数
1. sendto()
- 发送 UDP 数据报
c
#include <sys/socket.h>
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
- 功能:向指定目标地址发送 UDP 数据报(无需预先连接)。
- 参数:
- 前 4 个参数与
send()
相同。 dest_addr
:目标地址结构体指针。addrlen
:地址结构长度。
- 前 4 个参数与
- 返回值:成功返回发送的字节数,失败返回
-1
。 - 示例:
c
struct sockaddr_in server_addr; // 设置服务器地址... char *msg = "Hello, UDP server!"; sendto(sockfd, msg, strlen(msg), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
2. recvfrom()
- 接收 UDP 数据报
c
#include <sys/socket.h>
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
- 功能:接收 UDP 数据报,并获取发送方的地址信息。
- 参数:
- 前 4 个参数与
recv()
相同。 src_addr
:存储发送方地址的结构体指针(可设为NULL
)。addrlen
:地址结构长度的指针。
- 前 4 个参数与
- 返回值:成功返回接收的字节数,失败返回
-1
。 - 示例:
c
struct sockaddr_in client_addr; socklen_t client_addr_len = sizeof(client_addr); char buffer[1024]; int n = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&client_addr, &client_addr_len);
三、TCP 与 UDP 的核心区别
特性 | TCP | UDP |
---|---|---|
连接方式 | 面向连接(需三次握手) | 无连接 |
可靠性 | 可靠(自动重传、排序) | 不可靠(可能丢包、乱序) |
传输效率 | 较低(有确认机制) | 较高(无额外开销) |
数据形式 | 字节流(无边界) | 数据报(有边界) |
适用场景 | 文件传输、HTTP、SMTP 等 | 实时音视频、DNS、游戏等 |
核心函数 | connect() 、accept() 、send() 、recv() | sendto() 、recvfrom() |
四、常见错误处理
-
bind()
失败(EADDRINUSE
):- 原因:端口已被占用。
- 解决:使用
setsockopt()
设置SO_REUSEADDR
选项重用端口。
c
int opt = 1; setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
-
accept()
返回EAGAIN
或EWOULDBLOCK
:- 原因:在非阻塞模式下没有连接请求。
- 解决:继续处理其他事件或等待下一次
epoll_wait()
。
-
recv()
返回 0:- 原因:对方关闭了连接。
- 解决:关闭对应的套接字。
-
send()
/recv()
返回-1
且errno
为EINTR
:- 原因:系统调用被信号中断。
- 解决:重试操作。
五、总结
-
TCP 函数流程:
服务器:socket()
→bind()
→listen()
→accept()
→send()
/recv()
客户端:socket()
→connect()
→send()
/recv()
-
UDP 函数流程:
发送方:socket()
→sendto()
接收方:socket()
→bind()
→recvfrom()
掌握这些核心函数是实现网络编程的基础,不同函数的组合和参数设置决定了网络程序的行为(如阻塞 / 非阻塞、面向连接 / 无连接)。
分享