udp epoll服务器的设计

前言

       大家都知道,udp是无状态的。特点是简单高效。没有tcp三次握手等。但是在做udp服务器的时候,处理来自多个连接的udp请求时,需要check每个udp包,然后根据内容分给不同的session处理,这样就比较复杂,性能也特别低。那么是否可以使用epoll来管理多个udp连接呢?答案是肯定的。下面介绍具体方法。

具体实现

        1. 服务器创建socket,bind 端口,加入epoll,等待连接。

            设置reuseport

        2. 客户端首次连接上来,创建socket,connect到客户端ip,端口。注意客户端要bind 端口

        3. 新创建的socket,加入epoll管理。后续处理udp交互

伪代码流程

   服务器主流程

   struct epoll_event ev;
   struct epoll_event events[MAXEPOLLSIZE];
 
   /* 开启 socket */
   if ((listener = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
   {
     perror("socket create failed !");
     exit(1);
   }
   else
   {
     printf("socket create  success \n");
   }
 
   /*设置socket属性,端口可以重用*/
   int opt=SO_REUSEADDR;
   setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
 
   /* 设置非阻塞属性 */
   setnonblocking(listener);
   /* bind */
   bzero(&my_addr, sizeof(my_addr));
   my_addr.sin_family = PF_INET;
   my_addr.sin_port = htons(myport);
   my_addr.sin_addr.s_addr = INADDR_ANY;
   if (bind(listener, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) == -1) 
   {
     perror("bind");
     exit(1);
   } 
   else
   {
     printf("IP and port bind success, port:%d \n", myport);
   }
  
   /* 创建 epoll 句柄,把监听 socket 加入到 epoll 集合里 */
   kdpfd = epoll_create(MAXEPOLLSIZE);
   len = sizeof(struct sockaddr_in);
   ev.events = EPOLLIN | EPOLLET;
   ev.data.fd = listener;
   if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, listener, &ev) < 0) 
   {
     fprintf(stderr, "epoll set insertion error: fd = %d \n", listener);
     return -1;
   }
   else
   {
     printf("listen socket added in  epoll success \n");
   }
 
   while (1) 
   {
     /* 等待有事件发生 */
     nfds = epoll_wait(kdpfd, events, 10000, -1);
     if (nfds == -1)
     {
       perror("epoll_wait");
       break;
     }
 
     /* 处理所有事件 */
     for (n = 0; n < nfds; ++n)
     {
        if (events[n].data.fd == listener) 
        {
          /* 创建socket,connect client。加入epoll */
          accept_client(kdpfd,listener);
        }
	    else
	    {
          /* 处理udp包 */
		  msg_process(kdpfd,events[n].data.fd);  
	    }
     }
   }

连接客户端流程

    struct sockaddr_storage client_addr;
	socklen_t addr_size = sizeof(client_addr);
	char buf[1024];
	int ret = recvfrom(fd, buf,1024, 0, (struct sockaddr *)&client_addr, 
                    &addr_size);

	buf[ret] = '\0';
	char type=buf[0];
	char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
	ret = getnameinfo((struct sockaddr *)&client_addr, addr_size, hbuf,         
            sizeof(hbuf), \
		sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV);
	
 
	printf("recvfrom client [%s:%s] : %d\n", hbuf, sbuf, buf[0]);

    /* connect 客户端,并且加入epoll */
	int new_sock = udp_socket_connect(epollfd, (struct sockaddr_in*)&client_addr);

    /* 发送消息给客户端*/
	do_write(epollfd, new_sock, buf);

 总结

        udp服务器在好多媒体领域有应用。怎么高效处理udp报文是不得不考虑的问题

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

前进的蜗牛啊

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

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

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

打赏作者

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

抵扣说明:

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

余额充值