网站首页 > 技术文章 正文
在TCP Socket网络编程中,接收和发送的阻塞和非阻塞是指调用相应的接收和发送函数时,该函数在什么条件下会立即返回。
- 阻塞:
当调用阻塞式接收函数时,如果当前没有数据可用,函数会一直等待,直到有数据可用为止。类似地,当调用阻塞式发送函数时,如果发送缓冲区已满,函数会一直等待,直到缓冲区中有足够的空间来存储要发送的数据。
- 非阻塞:
当调用非阻塞式接收函数时,如果当前没有数据可用,函数会立即返回,返回值为0或错误码,应用程序需要不断调用该函数来检查是否有新数据到达。类似地,当调用非阻塞式发送函数时,如果发送缓冲区已满,函数会立即返回,返回值为0或错误码,应用程序需要不断调用该函数来检查缓冲区是否有足够的空间来存储要发送的数据。
阻塞和非阻塞的主要区别在于函数的调用方式和返回值,阻塞函数会一直等待,直到满足条件才会返回,而非阻塞函数会立即返回,无论条件是否满足。阻塞函数通常会使应用程序挂起,等待数据可用或缓冲区可用,而非阻塞函数则允许应用程序在等待数据到达的同时继续执行其他任务。
下面是使用阻塞和非阻塞方式发送和接收数据的代码示例:
阻塞模式:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main() {
int sockfd;
char buf[1024];
struct sockaddr_in server_addr;
// 创建socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
// 设置server地址
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
server_addr.sin_port = htons(8080);
// 连接server
if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
perror("connect");
exit(EXIT_FAILURE);
}
// 阻塞接收数据
int ret = recv(sockfd, buf, sizeof(buf), 0);
if (ret == -1) {
perror("recv");
exit(EXIT_FAILURE);
}
printf("Received: %s\n", buf);
char *msg = "Hello, Server!";
int len = strlen(msg);
// 阻塞发送数据
ret = send(sockfd, msg, len, 0);
if (ret == -1) {
perror("send");
exit(EXIT_FAILURE);
}
close(sockfd);
return 0;
}
非阻塞模式:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main() {
int sockfd;
char buf[1024];
struct sockaddr_in server_addr;
// 创建socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
// 设置为非阻塞模式
int flags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
// 设置server地址
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
server_addr.sin_port = htons(8080);
// 连接server
int ret = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret == -1 && errno != EINPROGRESS) {
perror("connect");
exit(EXIT_FAILURE);
}
// 等待连接完成
fd_set write_set;
FD_ZERO(&write_set);
FD_SET(sockfd, &write_set);
ret = select(sockfd + 1, NULL, &write_set, NULL, NULL);
if (ret == -1) {
perror("select");
exit(EXIT_FAILURE);
} else if (ret == 0) {
printf("Connection timed out.\n");
exit(EXIT_FAILURE);
}
// 非阻塞接收数据
while (1) {
ret = recv(sockfd, buf, sizeof(buf), 0);
if (ret == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
// 没有数据可读,等待一段时间再重试
usleep(1000);
continue;
} else {
perror("recv");
exit(EXIT_FAILURE);
}
} else if (ret == 0) {
printf("Server closed.\n");
break;
} else {
buf[ret] = '\0';
printf("Received: %s\n", buf);
break;
}
}
char *msg = "Hello, Server!";
int len = strlen(msg);
// 非阻塞发送数据
int sent = 0;
while (sent < len) {
ret = send(sockfd, msg + sent, len - sent, 0);
if (ret == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
// 发送缓冲区已满,等待一段时间再重试
usleep(1000);
continue;
} else {
perror("send");
exit(EXIT_FAILURE);
}
} else {
sent += ret;
}
}
close(sockfd);
return 0;
}
上面的代码中,首先通过`fcntl`函数将socket设置为非阻塞模式。在非阻塞模式下,当调用`connect`函数时,连接操作会立即返回,无论连接是否成功。此时需要使用`select`函数来等待连接完成,然后才能进行数据通信。
在非阻塞模式下,当调用`recv`函数时,如果没有数据可读,该函数会立即返回,返回值为-1,同时设置`errno`为`EAGAIN`或`EWOULDBLOCK`。此时需要等待一段时间再重试。同样,当调用`send`函数时,如果发送缓冲区已满,该函数会立即返回,返回值为-1,同时设置`errno`为`EAGAIN`或`EWOULDBLOCK`。此时需要等待一段时间再重试,直到所有数据发送完毕。
注意:根据自己的需求进行略作修改。
- 上一篇: 网络编程中,阻塞和非阻塞是什么意思?
- 下一篇: 阻塞/非阻塞——纸上得来终觉浅,绝知此事要躬行
猜你喜欢
- 2024-10-25 什么是喉梗阻 反流性食管炎嗓子疼怎么办
- 2024-10-25 阻塞列队详解!让你轻松理解阻塞列队
- 2024-10-25 【健康科普】认识阻塞性睡眠呼吸暂停低通气综合征
- 2024-10-25 气象科普|阻塞高压为何方神圣?后期它将给我国制造多轮冷空气
- 2024-10-25 非阻塞算法CAS 非阻塞函数
- 2024-10-25 为什么网络 I/O 会被阻塞?I/O 到底是什么?
- 2024-10-25 如何用Java设计阻塞队列,再说说ArrayBlocking和LinkedBlocking
- 2024-10-25 使用 Python Socket 实现非阻塞 I/O入门讲解
- 2024-10-25 梗阻性无精子症:多种选择,何为最佳?
- 2024-10-25 焦耳小偷 一个神奇的电路 焦耳小偷电路需要注意的地方
你 发表评论:
欢迎- 最近发表
-
- 吴谨言专访大反转!痛批耍大牌后竟翻红,六公主七连发力显真诚
- 港股2月28日物业股涨幅榜:CHINAOVSPPT涨1.72%位居首位
- 港股2月28日物业股午盘:CHINAOVSPPT涨1.72%位居首位
- 港股3月2日物业股涨幅榜:CHINAOVSPPT涨1.03%位居首位
- 港股3月2日物业股午盘:CHINAOVSPPT涨1.03%
- 天赋与心痛的背后:邓鸣贺成长悲剧引发的深刻反思
- 冯小刚女儿徐朵追星范丞丞 同框合照曝光惹人羡,回应网友尽显亲民
- “资本大佬”王冉:51岁娶小17岁童瑶,并承诺余生为娇妻保驾护航
- 港股3月2日物业股午盘:CHINAOVSPPT涨1.03%位居首位
- 「IT之家开箱」vivo S15 图赏:双镜云窗,盛夏风光
- 标签列表
-
- oraclesql优化 (66)
- 类的加载机制 (75)
- feignclient (62)
- 一致性hash算法 (71)
- dockfile (66)
- 锁机制 (57)
- javaresponse (60)
- 查看hive版本 (59)
- phpworkerman (57)
- spark算子 (58)
- vue双向绑定的原理 (68)
- springbootget请求 (58)
- docker网络三种模式 (67)
- spring控制反转 (71)
- data:image/jpeg (69)
- base64 (69)
- java分页 (64)
- kibanadocker (60)
- qabstracttablemodel (62)
- java生成pdf文件 (69)
- deletelater (62)
- com.aspose.words (58)
- android.mk (62)
- qopengl (73)
- epoch_millis (61)
本文暂时没有评论,来添加一个吧(●'◡'●)