send
函数在 Linux 系统调用中用于向已连接的套接字发送数据。关于 send
是否阻塞,这主要取决于套接字的类型以及是否设置了非阻塞标志。
send
时,如果发送缓冲区已满或者系统资源暂时不可用,进程会被挂起,直到可以发送数据为止。send
无法立即完成时,它会立即返回一个错误(通常是 EAGAIN
或 EWOULDBLOCK
),而不是挂起进程。fcntl
或 ioctl
函数设置 O_NONBLOCK
标志,可以将套接字设置为非阻塞。send
阻塞导致程序无法响应其他请求原因:默认情况下,send
是阻塞的,如果发送缓冲区已满,进程会被挂起,直到可以发送数据为止。
解决方法:
select
或 epoll
:
在发送数据之前,使用 select
或 epoll
检查套接字是否可写,只有在可写时才调用 send
。select
或 epoll
:
在发送数据之前,使用 select
或 epoll
检查套接字是否可写,只有在可写时才调用 send
。aio_send
等异步 I/O 函数,可以在不阻塞的情况下发送数据。以下是一个简单的非阻塞 send
示例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main() {
int sockfd;
struct sockaddr_in serv_addr;
socklen_t length;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
exit(1);
}
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8080);
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
perror("inet_pton");
exit(1);
}
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
perror("connect");
exit(1);
}
// 设置非阻塞模式
int flags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
const char *message = "Hello, World!";
int message_len = strlen(message);
while (1) {
int sent = send(sockfd, message, message_len, 0);
if (sent < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
printf("Send buffer is full, retrying...\n");
sleep(1);
continue;
} else {
perror("send");
break;
}
} else {
printf("Sent %d bytes\n", sent);
break;
}
}
close(sockfd);
return 0;
}
在这个示例中,我们创建了一个非阻塞的 TCP 套接字,并尝试发送数据。如果发送缓冲区已满,send
会立即返回 EAGAIN
或 EWOULDBLOCK
,程序会等待一段时间后重试。
希望这个回答能帮助你理解 send
函数的阻塞行为及其解决方法。
领取专属 10元无门槛券
手把手带您无忧上云