socket之recv() 阻塞&非阻塞
server.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/time.h> #include <netinet/in.h> #include <arpa/inet.h> #define MYPORT 8100 //连接时使用的端口 #define MAXCLINE 5 //连接队列中的个数 int conn_amount; //当前的连接数 int main(void) { int sock_fd,new_fd; //监听套接字 连接套接字 struct sockaddr_in server_addr; // 服务器的地址信息 struct sockaddr_in client_addr; //客户端的地址信息 socklen_t sin_size; int yes = 1; char buf[1024]; int ret; int i; //建立sock_fd套接字 if((sock_fd = socket(AF_INET,SOCK_STREAM,0))==-1) { perror("setsockopt"); exit(1); } printf("sockect_fd = %d\n", sock_fd); server_addr.sin_family = AF_INET; //主机字节序 server_addr.sin_port = htons(MYPORT); server_addr.sin_addr.s_addr = INADDR_ANY;//通配IP memset(server_addr.sin_zero,'\0',sizeof(server_addr.sin_zero)); if(bind(sock_fd,(struct sockaddr *)&server_addr,sizeof(server_addr)) == -1) { perror("bind error!\n"); exit(1); } if(listen(sock_fd,MAXCLINE)==-1) { perror("listen error!\n"); exit(1); } printf("listen port %d\n",MYPORT); new_fd = accept(sock_fd,(struct sockaddr *)NULL, NULL); if(new_fd == -1){ printf("accept socket error: %s\n",strerror(errno)); } int count = 0; int flag = 0; //MSG_DONTROUTE 绕过路由表查找。 //MSG_DONTWAIT 仅本操作非阻塞。 //MSG_OOB 发送或接收带外数据。 //MSG_PEEK 窥看外来消息。 //MSG_WAITALL 等待所有数据。 while(1) { printf("第 %d 次recv \n",++count); ret = recv(new_fd,buf,sizeof(buf),flag); if(ret > 0){ printf("收到 %d Byte[%s] \n",ret,buf); }else if (ret < 0){ if(ret == EAGAIN){ printf("没有数据可读\n"); } }else{ printf("连接断开\n"); break; } sleep(1); } }
client.c //客户端 #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <stdlib.h> #include <sys/time.h> #include <string.h> #define SERVER_IP "192.192.255.63" int main() { int client_sockfd; int len; struct sockaddr_in address;//服务器端网络地址结构体 int result; int count = 0; char msg[16]; client_sockfd = socket(AF_INET, SOCK_STREAM, 0);//建立客户端socket address.sin_family = AF_INET; //address.sin_addr.s_addr = inet_addr(SERVER_IP); address.sin_addr.s_addr =INADDR_ANY; address.sin_port = htons(8100); len = sizeof(address); result = connect(client_sockfd, (struct sockaddr *)&address, len); if(result == -1) { perror("oops: client2"); exit(1); } int flag = 0; while(1){ memset(msg,0,sizeof(msg)); sprintf(msg,"client-> send%d",count++); send(client_sockfd, msg, sizeof(msg),flag); printf("client have send %s \n",msg); sleep(15); } close(client_sockfd); return 0; }
- recv 默认是阻塞还是非阻塞?
这里把client发送一次消息后(为了证明server能收到),sleep150s,如果recv一直轮训接收那就是非阻塞,如果一直等,那就是默认阻塞,这里recv flag = 0;
第一次收到后,一直阻塞,所以默认是阻塞的,即收不到消息一直等待;
- 其他flag参数
2.1 MSG_DONTWAIT
修改server.c - > int flag = MSG_DONTWAIT;
这里的执行结果可以看到此时recv不是一直等待,而是返回进行了后续的recv操作;
2.2 MSG_WAITALL
修改server.c - > int flag = MSG_WAITALL; char buf[24];
server.c 一次需要接收24 Byte,而client一次发送才14Byte,看recv如何表现
每次接收24 Byte(buf的size)才返回,即MSG_WAITALL使用的时候,把recv的buf填满才返回;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)