网络编程 之 MSG_WAITALL

本文详细介绍了MSG_WAITALL标志在套接字编程中的作用,当recv函数设置该标志时,它会阻塞直到接收到请求的全部字节数,除非遇到中断、错误、连接断开或数据类型不匹配。通过示例代码展示了如何在服务器端使用MSG_WAITALL接收客户端数据,并讨论了其在处理粘包问题上的局限性。
摘要由CSDN通过智能技术生成

一、MSG_WAITALL 理解

MSG_WAITALL标志,如果recv设置了这个标志,当没有收到请求的字节数时,recv函数会阻塞。然而,当被信号打断,或者发生了错误,或者断开了连接,或者接收到的下一个数据和已经接收的数据的数据类型不一致时,recv函数即使没有收到请求的字节数,也会返回,返回一个错误。

二、代码示例

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

int server_init(const char *ipstr, ushort port, int backlog)
{
	//创建流式IPv6套接字
	int s = socket(AF_INET6, SOCK_STREAM, 0);
	if(-1 == s){
		perror("socket");
		return -1;
	}

	//初始本地地址结构
	struct sockaddr_in6 addr = {
		.sin6_family	= AF_INET6,		//IPv6
		.sin6_port		= htons(port),	//服务器端口号
		//.sin6_scope_id	= 0,
	};
	
	//服务器ip,in6addr_any是一个宏,可以是本地任意IP
	//给监听套接字绑定的IP是in6addr_any,有两个好处
	//1.本地有多个网卡,那么客户端可以通过任意网卡连接的网络来连接服务器
	//2.服务器运行在不同主机上,不用改代码重新编译,把当前主机的IP告诉客户端就可以了
	//弊端:由于没有指定唯一IP,故此,网络收发包的时候要路由下(找哪个网卡来收发数据)
	addr.sin6_addr =in6addr_any;
	if(ipstr){
		if(inet_pton(AF_INET6, ipstr, addr.sin6_addr.s6_addr16) <= 0){
			addr.sin6_addr = in6addr_any;
		}else{
			addr.sin6_scope_id = 0;//网卡的id 
		}
	}
	//地址结构的长度
	socklen_t len = sizeof(addr);
	//给套接字绑定本地ip和端口
	if(0 > bind(s, (struct sockaddr *)&addr, len)){
		perror("bind");
		goto ERR_STEP;
	}

	//设置监听数
	if(0 > listen(s, backlog)){
		perror("listen");
		goto ERR_STEP;
	}

	return s;

ERR_STEP:
	close(s);
	return -1;
}

int main()
{
	int s = server_init(NULL, 59999, 10);
	if(0 > s){
		return -1;
	}

	printf("wait for client.\n");

	struct sockaddr_in6 c_addr;
	//c_len输入参数:告诉accept地址有多少字节数;输出参数:实际接收的字节数
	socklen_t c_len = sizeof(c_addr);
	int rws = accept(s, (struct sockaddr *)&c_addr, &c_len);
	if(0 > rws){
		perror("accept");
		goto ERR_STEP;
	}

	//把客户端的IP转成字符串IP并打印
	char ipstr[INET6_ADDRSTRLEN];
	if(inet_ntop(AF_INET6, c_addr.sin6_addr.s6_addr16, ipstr, INET6_ADDRSTRLEN)){
		printf("client ip : %s\n", ipstr);
	}
	//打印客户端的端口
	printf("client port : %u\n", ntohs(c_addr.sin6_port));

//如果知道发送对端发送的字节,使用MSG_WAITALL就可以解决粘包问题
//强调:MSG_WAITALL不是解决粘包问题用的
//熟悉粘包造成原因:内核协议层会把应用传递的缓存数据依据协议拆包、组包,从而造成接收端少收,多收
//从而造成粘包
	while(1){
	#define MAX (1024*1024)
		static char buf[MAX];
		//接收数据:从套接字接收缓存读出数据
		//使用MSG_WAITALL标志:表示,想读出MAX字节数据,则一定要读出才会返回
		//否则返回就是出错或连接断开了
		int num = recv(rws, buf, MAX, MSG_WAITALL);
		if(-1 == num){
			//本地网络出现问题
			perror("read");
			break;
		}else if(0 == num){
			//连接断开
			printf("link off\n");
			break;
		}

		printf("recv %d bytes\n", num);
	}

	close(rws);


ERR_STEP:
	close(s);
	printf("server is leave.\n");
	return 0;
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

<( ̄︶ ̄)Okay.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值