前言:发送RTP码流时,通常需要将视频数据切分成多个MTU内大小的块再使用socket发出去。如果是每次调用send函数只发送一个RTP包,send函数调用会很频繁从而导致性能下降。这时需要使用sendmsg 和 sendmmsg函数批量发送多个RTP达到优化效果。
sendmsg : 对于发送RTP包,sendmsg只能用在TCP发送场景,如果UDP也使用将导致所有RTP包被当成一个UDP包发出,见代码1。
sendmmsg: 可以一次发送多个RTP包,且每个RTP包使用一个UDP包封装。两个函数都可以向sendto那样无链接发送,需要在struct msghdr结构体中将msg_name和msg_namelen填sendto最好两个参数即可。创建连接效率会更高,见代码2。
代码1:
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/times.h>
#define MAX_SEG 20
#define SEG_SIZE 1500
#define PKG_NUM 10000*100
int
main(void)
{
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(28000);
inet_pton(AF_INET, "192.168.21.173", &server_addr.sin_addr.s_addr);
if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1)
{
printf("connect error!\n");
return -1;
}
char data[SEG_SIZE];
memset(data, 0xfe, sizeof(data));
struct iovec iovs[MAX_SEG];
memset(iovs, 0, sizeof(iovs));
int i;
for (i = 0; i < MAX_SEG; ++i)
{
iovs[i].iov_base = data;
iovs[i].iov_len = sizeof(data);
}
struct msghdr msg_hdr;
memset(&msg_hdr, 0, sizeof(msg_hdr));
msg_hdr.msg_iov = iovs;
msg_hdr.msg_iovlen = MAX_SEG;
time_t start = times(0);
unsigned int send_num = 0;
while (1)//send_num < PKG_NUM)
{
if(0 > sendmsg(sockfd, &msg_hdr, 0))
{
printf("sendmmsg error\n");
//break;
}
send_num += MAX_SEG;
}
printf("use time:%u0ms\n", times(0)-start);
close(sockfd);
return 0;
}
代码2:
//#define _GNU_SOURCE
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/times.h>
#include <iostream>
#define MAX_SEG 20
#define SEG_SIZE 1500
#define PKG_NUM 10000*100
/*
struct mmsghdr
{
struct msghdr msg_hdr;
unsigned int msg_len;
};
*/
int
main(void)
{
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(28000);
inet_pton(AF_INET, "192.168.21.173", &server_addr.sin_addr.s_addr);
if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1)
{
printf("connect error!\n");
return -1;
}
struct iovec iovs[MAX_SEG];
struct mmsghdr mmsg[MAX_SEG];
bzero(&iovs, sizeof(iovs));
bzero(&mmsg, sizeof(mmsg));
char data[SEG_SIZE];
memset(data, 0xfe, sizeof(data));
int i;
for (i = 0; i < MAX_SEG; ++i)
{
iovs[i].iov_base = data;
iovs[i].iov_len = sizeof(data);
mmsg[i].msg_hdr.msg_iov = iovs + i;
mmsg[i].msg_hdr.msg_iovlen = 1;
}
time_t start = times(0);
unsigned int send_num = 0;
while (1)//send_num < PKG_NUM)
{
if(0 > sendmmsg(sockfd, mmsg, MAX_SEG, 0))
{
printf("sendmmsg error\n");
//break;
}
send_num += MAX_SEG;
}
printf("use time:%u0ms\n", times(0)-start);
close(sockfd);
return 0;
}