LINUX编程实战指发送UDP消息

简介: LINUX编程实战指发送UDP消息

最近调试媒体服务器,发现被叫的媒体流总是抖动的厉害,不清楚是网络原因还是媒体服务器的代码问题。


为了方便排查问题,我编写了一个UDP发送的小工具。根据传入目的地的IP、PORT和发送的时长。该工具就可以按照20ms的间隔进行重复发送RTP流。


编程思路:


首先初始化本端udp的socket套接字:


memset(buf,1,sizeof(buf));
  char * desip = argv[1];
  int destport = atoi(argv[2]);
  int sec = atoi(argv[3]);
  int count = sec * 1000 / 20;
  int fd=-1;
  fd=socket(AF_INET,SOCK_DGRAM,0);
  fcntl(fd,F_SETFL,O_NDELAY);
  int reuse_addr_flag=1;
  int success=setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char *)&reuse_addr_flag,sizeof(reuse_addr_flag));
  if(success<0)
  {
      perror("udp setsockopt(SO_REUSEADDR): ");
      close(fd);
      return 0;
  }
   int sendBufSize,sendBufLength;
   sendBufSize=4*1024*1024;
   sendBufLength=sizeof sendBufSize;
   if(setsockopt(fd,SOL_SOCKET,SO_SNDBUF,(char*)&sendBufSize,sendBufLength)<0)
   {
      perror("udp setsockopt(SO_SNDBUF): ");
      return 0;
   }
   if(setsockopt(fd,SOL_SOCKET,SO_RCVBUF,(char*)&sendBufSize,sendBufLength)<0)
   {
      perror("udp setsockopt(SO_RCVBUF): ");
      return 0;
   }
   struct sockaddr_in localaddr;
   in_addr_t net_addr=inet_addr("0.0.0.0");
   //ntohl(l_ipv4.ip_dw)
   memset(&localaddr,0,sizeof(struct sockaddr_in));
   localaddr.sin_family = AF_INET;
   localaddr.sin_port = 30008;
   memcpy((struct sockaddr*)&localaddr.sin_addr,(void *)(&net_addr),sizeof(net_addr));
   if (bind(fd,(struct sockaddr *)&localaddr,sizeof(struct sockaddr_in)) != 0)
   {
    return 0;
   }


根据目的端的IP、PORT设置套接字:


int success;
   struct sockaddr *pDestAddr = NULL;
   struct sockaddr_in destAddr;
   int len;
   memset(&destAddr,0,sizeof(struct sockaddr_in));
   in_addr_t net_addr=inet_addr(host);
   destAddr.sin_family = AF_INET;            
   destAddr.sin_port = htons(port);
   memcpy((struct sockaddr*)&destAddr.sin_addr,(void *)(&net_addr),sizeof(net_addr));
   pDestAddr = (struct sockaddr*)&destAddr;
   len = sizeof(destAddr);


最后调用sendto函数,发送UDP数据


success = sendto(fd,buffer,length,0, pDestAddr, len);
   if(success<0)
   {
      char *buf = new char[length + 128];
      sprintf(buf, "sendto(%d, %s, %d, %s, %d):", fd, buffer, length, host, port);
      perror(buf);
      delete []buf;
   }


完整的代码如下:


#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <strings.h> 
#include <signal.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <time.h>
#include <sys/time.h>
#include <unistd.h>
void sendUDPMsg(int fd,char* host,unsigned short port,char* buffer,int length);
int main(int argc,char* argv[])
{
  char buf[640]={1};
  memset(buf,1,sizeof(buf));
  char * desip = argv[1];
  int destport = atoi(argv[2]);
  int sec = atoi(argv[3]);
  int count = sec * 1000 / 20;
  int fd=-1;
  fd=socket(AF_INET,SOCK_DGRAM,0);
  fcntl(fd,F_SETFL,O_NDELAY);
  int reuse_addr_flag=1;
  int success=setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char *)&reuse_addr_flag,sizeof(reuse_addr_flag));
  if(success<0)
  {
      perror("udp setsockopt(SO_REUSEADDR): ");
      close(fd);
      return 0;
  }
   int sendBufSize,sendBufLength;
   sendBufSize=4*1024*1024;
   sendBufLength=sizeof sendBufSize;
   if(setsockopt(fd,SOL_SOCKET,SO_SNDBUF,(char*)&sendBufSize,sendBufLength)<0)
   {
      perror("udp setsockopt(SO_SNDBUF): ");
      return 0;
   }
   if(setsockopt(fd,SOL_SOCKET,SO_RCVBUF,(char*)&sendBufSize,sendBufLength)<0)
   {
      perror("udp setsockopt(SO_RCVBUF): ");
      return 0;
   }
   struct sockaddr_in localaddr;
   in_addr_t net_addr=inet_addr("0.0.0.0");
   //ntohl(l_ipv4.ip_dw)
   memset(&localaddr,0,sizeof(struct sockaddr_in));
   localaddr.sin_family = AF_INET;
   localaddr.sin_port = 30008;
   memcpy((struct sockaddr*)&localaddr.sin_addr,(void *)(&net_addr),sizeof(net_addr));
   if (bind(fd,(struct sockaddr *)&localaddr,sizeof(struct sockaddr_in)) != 0)
   {
    return 0;
   }
   int i =0;
   for(i=0;i<count;i++)
   {
     sendUDPMsg(fd,desip,destport,buf,sizeof(buf));
     usleep(1000 * 20);
   }
   return 1;
}
void sendUDPMsg(int fd,char* host,unsigned short port,char* buffer,int length)
{   
   int success;
   struct sockaddr *pDestAddr = NULL;
   struct sockaddr_in destAddr;
   int len;
   memset(&destAddr,0,sizeof(struct sockaddr_in));
   in_addr_t net_addr=inet_addr(host);
   destAddr.sin_family = AF_INET;            
   destAddr.sin_port = htons(port);
   memcpy((struct sockaddr*)&destAddr.sin_addr,(void *)(&net_addr),sizeof(net_addr));
   pDestAddr = (struct sockaddr*)&destAddr;
   len = sizeof(destAddr);
   success = sendto(fd,buffer,length,0, pDestAddr, len);
   if(success<0)
   {
      char *buf = new char[length + 128];
      sprintf(buf, "sendto(%d, %s, %d, %s, %d):", fd, buffer, length, host, port);
      perror(buf);
      delete []buf;
   }
}


代码编译方法如下:


g++ -g testrtpudp.c -o testrtp


使用方法如下:


./testrtp 192.168.2.77 3950 1


相关文章
|
5天前
|
机器学习/深度学习 Unix Java
技术笔记:Linux之Shell脚本编程(一)
技术笔记:Linux之Shell脚本编程(一)
|
5天前
|
Java Linux 网络安全
在Linux上搭建Maven仓库的实战教程
在Linux上搭建Maven仓库的实战教程
20 0
|
9天前
|
NoSQL Linux 程序员
Linux objdump命令:深入解析与实战应用
`objdump`是Linux下的反汇编工具,用于将二进制文件转换为汇编代码,便于理解程序底层。它可以反汇编目标文件、可执行文件和库,支持多种参数,如显示符号表(-t)、反汇编代码(-d)、源代码与汇编混合视图(-S)。在实践中,结合-g编译选项和特定段(-j)反汇编,能辅助调试和分析。使用时注意包含调试信息,选择适当参数,并与其他工具(如gdb)配合使用。
|
13天前
|
消息中间件 运维 监控
Linux命令lsipc:深入解析与实战应用
`lsipc` (通常指 `ipcs`) 是Linux命令,用于查看系统中的IPC资源,包括消息队列、信号量和共享内存。它显示详细信息,支持过滤,并且需要相应权限。示例用法:显示共享内存(`-m`)、查询消息队列(`-q -i ID`)、查看关联进程(`-m -p`)。注意权限、操作影响及定期监控。结合`ipcrm`等工具可进行更深入管理。
|
18天前
|
Linux Windows 虚拟化
【Linux环境搭建实战手册】:打造高效开发空间的秘籍
【Linux环境搭建实战手册】:打造高效开发空间的秘籍
|
21天前
|
消息中间件 存储 监控
实战Linux I/O多路复用:借助epoll,单线程高效管理10,000+并发连接
本文介绍了如何使用Linux的I/O多路复用技术`epoll`来高效管理超过10,000个并发连接。`epoll`允许单线程监控大量文件描述符,显著提高了资源利用率。文章详细阐述了`epoll`的几个关键接口,包括`epoll_create`、`epoll_ctl`和`epoll_wait`,以及它们在处理并发连接中的作用。此外,还探讨了`epoll`在高并发TCP服务场景的应用,展示了如何通过`epoll`和线程/协程池来构建服务框架。
162 3
|
21天前
|
算法 Linux 测试技术
Linux编程:测试-高效内存复制与随机数生成的性能
该文探讨了软件工程中的性能优化,重点关注内存复制和随机数生成。文章通过测试指出,`g_memmove`在内存复制中表现出显著优势,比简单for循环快约32倍。在随机数生成方面,`GRand`库在1000万次循环中的效率超过传统`rand()`。文中提供了测试代码和Makefile,建议在性能关键场景中使用`memcpy`、`g_memmove`以及高效的随机数生成库。
|
24天前
|
关系型数据库 MySQL Linux
Linux 命令 `db_upgrade` 详解与实战
`db_upgrade` 是一个自定义数据库升级命令,用于更新数据库结构和版本。它包括检查当前版本、备份、执行升级、更新版本信息和验证。基本语法是 `db_upgrade [OPTIONS]`,支持 `-b`(备份)、`-f`(强制升级)、`-v`(详细信息)等选项。在实战中,先备份数据库,然后使用 `db_upgrade` 命令升级,并验证结果。注意在生产环境升级前进行测试。虽然不是标准命令,但理解其用法有助于应对数据库升级。
|
25天前
|
消息中间件 存储 缓存
【嵌入式软件工程师面经】Linux系统编程(线程进程)
【嵌入式软件工程师面经】Linux系统编程(线程进程)
38 1
|
27天前
|
移动开发 网络协议 视频直播
25.Python 网络编程:TCP和UDP编程
25.Python 网络编程:TCP和UDP编程
23 2