首页 > 代码库 > 数据报截断

数据报截断

当一个到达的UDP数据报超过应用程序提供的缓冲区容量时,recvmsg在其 msghdr结构的msg_flags成员上设置MSG_TRUNC标志。
所有支持msghdr结构及其msg_flags成员的实现都提供这种通知。但并非所有实现都以同一种方式处理超过预期长度的UDP数据报
存在三种情况:
1.丢弃超出部分的字节并向应用进程返回MSG_TRUNC标志,调用recvmsg可以接收这个标志
2.丢弃超出部分的字节但不通知这个标志

3.保留超出部分的字节并在同一套接字后续的读操作中返回它们


实例
客户程序


#include <iostream>
#include <strings.h>
#include <string.h>
#include <sys/types.h>     
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
using namespace std;

struct buf
{
	int  order;
	unsigned char data[10];
	int  add;
};

int main()
{
	int sockfd;
	int r;
	int on = 1;
	struct sockaddr_in saddr;
	struct buf buf;
	
	sockfd =  socket(AF_INET, SOCK_DGRAM, 0);
	setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
	bzero(&saddr, sizeof(saddr));
	saddr.sin_family = AF_INET;
	saddr.sin_addr.s_addr = inet_addr("192.168.199.255");
	saddr.sin_port = htons(9999);
	
	buf.order = 1;
	strcpy((char*)buf.data, "Hello");
	buf.add = 2;
	
	r = sendto(sockfd, &buf, sizeof(buf), 0,
			   (struct sockaddr*)&saddr, sizeof(saddr));
	if (r == -1)
	{
		perror("sendto error");
		exit(-1);
	}
	cout << "finish" << endl;
	return 0;
}


服务程序

#include <iostream>
#include <strings.h>
#include <string.h>
#include <sys/types.h>     
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
using namespace std;

struct buf
{
	int  order;
	unsigned char data[10];
};

int main()
{
	int       sockfd;
	int       r;
	socklen_t len;
	struct    sockaddr_in saddr;
	struct    buf buf;
	struct    sockaddr_in caddr;
	struct    msghdr msg;
	struct    iovec iov;
	struct    cmsghdr *cmptr;
	union   
    {  
        struct cmsghdr cm;  
        char   control[CMSG_SPACE(sizeof(int))];  
    } control_un;  
	
	sockfd =  socket(AF_INET, SOCK_DGRAM, 0);
	bzero(&saddr, sizeof(saddr));
	saddr.sin_family = AF_INET;
	saddr.sin_addr.s_addr = htonl(INADDR_ANY);
	saddr.sin_port = htons(9999);
	if (bind(sockfd, (struct sockaddr*)&saddr, sizeof(saddr)) < 0)
	{
		perror("bind error");
		exit(-1);
	}

	msg.msg_name = NULL;            
	msg.msg_namelen = 0;	
	iov.iov_base = &buf;
	iov.iov_len = sizeof(buf);
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;
	
	msg.msg_control = control_un.control;  
    msg.msg_controllen = sizeof(control_un.control);  
    msg.msg_flags = 0;
	
	while (1)
	{
		r = recvmsg(sockfd, &msg, 0);
		if (r < 0)
		{
			perror("recvfrom error");
			exit(-1);
		}
		cout << buf.order << endl;
		cout << buf.data << endl;
		cout << endl;	
		
		int recv_len = r;
		//判断是否发生数据报截断
		if (msg.msg_flags == MSG_TRUNC)
		{
			cout << "数据报截断" << endl;
			unsigned char temp_buf[200];
			r = recvfrom(sockfd, &temp_buf, sizeof(temp_buf), 0,
						 NULL, 0);
			if (r == recv_len+sizeof(int))
			{
				cout << "超出的部分被保留" << endl;
			} else {
				cout << "超出的部分被丢弃" << endl;
			}
		}
	}
	
	return 0;
}

执行结果:

发送第一个数据报

发送第二个数据报

发送第三个数据报