免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3129 | 回复: 6
打印 上一主题 下一主题

[C] linux epoll 发送函数封装问题请教... [复制链接]

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2015-04-18 10:00 |只看该作者 |倒序浏览

大概流程就是:main.c 主文件运行后,接受客户端连接,当客户端发相应命令过来后,在tcp.c 文件中解析后,调用function.c文件中的处理函数:Receive_Process()。
原来我的想法是,在function处理完成后,通过Receive_Process()函数再把结果返回,
[code=c]void Receive_Process(int conn_fd,unsigned char*  buff_r,unsigned char*  buff_w)[/code]
如果这样的话,就没这些问题了,处理的结果,我在tcp.c文件中,通过 “unsigned char*  buff_w” 可以拿到,送给PC就完事了。

现在同事要求不这么干,即不通过Receive_Process()进、出方式,把结果返回。而是要在fuction.c中(当然也可能其他文件中可以调用发送函数,把结果送给PC)把结果直接送给PC端...


(在另个帖子里可能没描述清楚)

主文件:
主要就是网上找到一段代码,简单调整了一下。

  1. #include "tcp.h"
  2. int main(int argc, char * argv[])   
  3. {       
  4.                 tcp_initialize();
  5.                 epoll_fd_tcp=create_epoll_tcp(MAX_EVENTS_TCP);         
  6.           while(1)
  7.           {
  8.                    do_process_tcp_nowhile();
  9.                    sleep(1);
  10.           }         
  11. }  
复制代码
处理文件:function.c

  1. #include "function.h"

  2. void Receive_Process(int conn_fd,unsigned char*  buff_r,unsigned char*  buff_w)
  3. {
  4.         unsigned char CmdKey;
  5.         unsigned char length;
  6.         int len,i;
  7.   len = buff_r[1];
  8.         CmdKey = buff_r[2];       
  9.         printf("packet len is : %02X\n",buff_r[1]);
  10.         printf("cmdkey is : %02X\n",buff_r[2]);
  11.         for(i=0;i<len;i++)
  12.                      buff_r[i]=buff_r[i+1];
  13.              for(i=0;i<len;i++)
  14.                      printf("%02X ",buff_r[i]);
  15.   printf("\n");
  16. switch(CmdKey)
  17.         {                               
  18.                 case 0x02:
  19.                         //write_spi_arm_to_fpga_array(5,buff_r,buff_w);
  20.                      [color=#FF0000]  // 根据命令,与FPGA交互后,将返回结果送给PC端,下面是模拟的数据。[/color]
  21.                         buff_w[0]=0x08;
  22.                         buff_w[1]=0x03;
  23.                         buff_w[2]=0x8c;
  24.                         buff_w[3]=0x00;
  25.                         buff_w[4]=0x00;
  26.                         //send to pc
  27.                        [color=#FF0000] tcp_send_data_to_pc(5 buff_w);[/color]
  28.                        // 无发完成发送任务,这个函数只能在tcp.c文件中能正常,出了tcp.c文件就不行了。
  29.                         printf("CMD_GET_VERSION OK \n");               
  30.                         break;
  31.                 default:                                               
  32.                         break;
  33.         }               
  34. }
复制代码
TCP文件: tcp.c

  1. #include "tcp.h"

  2. struct epoll_event events[MAX_EVENTS_TCP];// 事件监听队列


  3. int server_sock_fd_tcp;// 服务器端套接字   
  4. int client_sock_fd_tcp;// 客户端套接字      
  5. int nfds_tcp;// epoll监听事件发生的个数
  6. int len_recv_data_tcp;
  7. struct sockaddr_in host_addr_tcp;   // 服务器网络地址结构体   
  8. struct sockaddr_in remote_addr_tcp; // 客户端网络地址结构体   
  9. int sin_size;   
  10. unsigned char send_data_buffer_size_tcp[BUFFER_SIZE_TCP];  // 数据传送的缓冲区  
  11. unsigned char retn_data_buffer_size_tcp[BUFFER_SIZE_TCP];   
  12. int m=0;
  13. int len;
  14. //设置句柄为非阻塞方式
  15. int setnonblocking(int sockfd)  
  16. {  
  17. if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK) == -1)  
  18. {  
  19.     return -1;  
  20. }  
  21.     return 0;  
  22. }

  23. int tcp_send_data_to_pc(int len,char* buffer)
  24. {       
  25.                 printf("in while n == %d \n",n);
  26.                 send(events[n].data.fd,buffer,4,0);               
  27.                 ev.events = EPOLLIN;
  28.                 ev.data.fd = events[n].data.fd;
  29.     epoll_ctl(epoll_fd_tcp, EPOLL_CTL_MOD, ev.data.fd, &ev);
  30. }

  31. void tcp_initialize()
  32. {
  33.     struct rlimit rt;
  34.    
  35.     /* 设置每个进程允许打开的最大文件数 */  
  36.     rt.rlim_max = rt.rlim_cur = 1024;  
  37.     if (setrlimit(RLIMIT_NOFILE, &rt) == -1)   
  38.                 {  
  39.         perror("setrlimit");  
  40.         exit(1);  
  41.     }  
  42.     else   
  43.     {  
  44.         printf("setrlimit ok! \n");  
  45.     }  
  46.    
  47.     // 创建服务器端套接字--IPv4协议,面向连接通信,TCP协议
  48.     if((server_sock_fd_tcp=socket(PF_INET,SOCK_STREAM,0))<0)   
  49.     {     
  50.         perror("socket");   
  51.         //return 1;   
  52.     }
  53.     else
  54.     {
  55.             printf("Tcp server socket ok...\n");
  56.     }
  57.            
  58.             // 设置 socket属性,端口可以重用   
  59.   
  60.           int opt=SO_REUSEADDR;
  61.           setsockopt(server_sock_fd_tcp,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
  62.           setnonblocking(server_sock_fd_tcp);
  63.            
  64.     memset(&host_addr_tcp,0,sizeof(host_addr_tcp)); // 数据初始化--清零      
  65.     host_addr_tcp.sin_family=PF_INET; // 设置为IP通信   
  66.     host_addr_tcp.sin_addr.s_addr=inet_addr(HOST_IP_ADDRESS_TCP);// 服务器IP地址--允许连接到所有本地地址上   
  67.     host_addr_tcp.sin_port=htons(HOST_PORT_TCP); // 服务器端口号  
  68.    
  69.     // 将套接字绑定到服务器的网络地址上
  70.     if (bind(server_sock_fd_tcp,(struct sockaddr *)&host_addr_tcp,sizeof(struct sockaddr))<0)   
  71.     {   
  72.         perror("bind");   
  73.         //return 1;   
  74.     }
  75.     else
  76.     {
  77.             printf("Tcp server bind ok...\n");
  78.             printf("IP  : %s   \n", inet_ntoa(host_addr_tcp.sin_addr));
  79.             printf("port: %d \n",ntohs(host_addr_tcp.sin_port));
  80.     }
  81.     // 监听连接请求--监听队列长度为5
  82.     listen(server_sock_fd_tcp,64);   
  83.     sin_size=sizeof(struct sockaddr_in);
  84.        
  85. }

  86. // 创建一个epoll句柄
  87. int create_epoll_tcp(unsigned int event_num)
  88.   {       
  89.           int epoll_fd;
  90.                 epoll_fd=epoll_create(event_num);
  91.                 if(epoll_fd==-1)
  92.                 {
  93.                         perror("epoll_create failed");                       
  94.                 }
  95.                 ev.events=EPOLLIN | EPOLLET;
  96.                 ev.data.fd=server_sock_fd_tcp;
  97.                 // 向epoll注册server_sockfd监听事件
  98.                 if(epoll_ctl(epoll_fd,EPOLL_CTL_ADD,server_sock_fd_tcp,&ev)==-1)
  99.                 {
  100.                         perror("epll_ctl:server_sock_fd_tcp register failed");                       
  101.                 }
  102.                 else
  103.           {
  104.             printf("socket adding in  epoll success! \n");
  105.           }
  106.                 return epoll_fd;
  107. }

  108. void do_process_tcp_nowhile()
  109. {                         
  110.                         // 等待事件发生
  111.                         nfds_tcp=epoll_wait(epoll_fd_tcp,events,1024,-1);
  112.                         if(nfds_tcp==-1)
  113.                         {
  114.                                 perror("start epoll_wait failed");
  115.                                 //exit(EXIT_FAILURE);
  116.                         }
  117.                         else
  118.                         {
  119.                                         printf(" epoll nfds_tcp = %d   \n",nfds_tcp);
  120.                         }
  121.                        
  122.                         for(n=0;n<nfds_tcp;++n)
  123.                         {
  124.                                 printf(" for loop epoll nfds_tcp = %d   \n",nfds_tcp);
  125.                                 // 客户端有新的连接请求
  126.                                 if(events[n].data.fd == server_sock_fd_tcp)
  127.                                 {
  128.                                         // 等待客户端连接请求到达
  129.                       if((client_sock_fd_tcp=accept(server_sock_fd_tcp,(struct sockaddr *)&remote_addr_tcp,&sin_size))<0)
  130.                                         {   
  131.                                                 perror("accept client_sock_fd_tcp failed");   
  132.                                                 exit(EXIT_FAILURE);
  133.                                         }
  134.                                         // 向epoll注册client_sockfd监听事件
  135.                                         setnonblocking(client_sock_fd_tcp);
  136.                                         ev.events=EPOLLIN | EPOLLET;
  137.                                         ev.data.fd=client_sock_fd_tcp;
  138.                                         if(epoll_ctl(epoll_fd_tcp,EPOLL_CTL_ADD,client_sock_fd_tcp,&ev)==-1)
  139.                                         {
  140.                                                 perror("epoll_ctl:client_sock_fd_tcp register failed");                                               
  141.                                         }
  142.                                         printf("accept client %s\n",inet_ntoa(remote_addr_tcp.sin_addr));                                               
  143.                                 }
  144.                                 else if(events[n].events & EPOLLIN)
  145.                                 {
  146.                                         // 客户端有数据发送过来
  147.                                         sprintf(send_data_buffer_size_tcp,"");
  148.                                         //sin_size=sizeof(remote_addr_tcp);
  149.                                
  150.                                         len_recv_data_tcp=recv(events[n].data.fd,send_data_buffer_size_tcp,BUFFER_SIZE_TCP,0);
  151.                                         if(len_recv_data_tcp<=0)
  152.                                         {
  153.                                                 printf("close id is : %d \n",events[n].data.fd);                                       
  154.                                                 if(epoll_ctl(epoll_fd_tcp,EPOLL_CTL_DEL,events[n].data.fd,&ev)==0)
  155.                                                 {
  156.                                                         printf("delete ok \n");
  157.                                                         close(events[n].data.fd);
  158.                                                 }
  159.                                                 else
  160.                                                 {
  161.                                                         printf("delete error \n");
  162.                                                 }
  163.                                         }
  164.                                         else
  165.                                         {//[color=#FF0000]处理PC来的命令包,,调用fuction.c文件中的 Receive_Process()函数[/color]
  166.                                      Receive_Process(4,send_data_buffer_size_tcp,retn_data_buffer_size_tcp);
  167.                                     
  168.                                                 ev.data.fd = events[n].data.fd;
  169.             ev.events = EPOLLOUT|EPOLLET;
  170.             epoll_ctl(epoll_fd_tcp, EPOLL_CTL_MOD, events[n].data.fd, &ev);                                                       
  171.                                         }
  172.                                 }
  173.                                 else if(events[n].events & EPOLLOUT)//发送
  174.                                 {                                       
  175.                                         tcp_send_data_to_pc(4,send_data_buffer_size_tcp);        [color=#FF0000]//这个地方就正常        [/color]                       
  176.                                 }
  177.                         }                       
  178.                
  179.                 if(server_sock_fd_tcp>0)
  180.                 {
  181.                         printf("socket close \n");
  182.                         shutdown(server_sock_fd_tcp,SHUT_RDWR);
  183.                         close(server_sock_fd_tcp);
  184.                 }
  185.                
  186. }
复制代码
tcp.h头文件

  1. #include <arpa/inet.h>  
  2. #include <fcntl.h>  
  3. #include <sys/epoll.h>  
  4. #include <sys/time.h>  
  5. #include <sys/resource.h>  

  6. #define BUFFER_SIZE_TCP 40
  7. #define MAX_EVENTS_TCP 10
  8. #define HOST_IP_ADDRESS_TCP "192.168.1.200"
  9. #define HOST_PORT_TCP 4530

  10. int n;
  11. struct epoll_event ev;// epoll事件结构体

  12. int epoll_fd_tcp;
  13. int tcp_send_data_to_pc(int len,char* buffer);
  14. void tcp_initialize();
  15. int create_epoll_tcp(unsigned int event_num);
  16. void do_process_tcp_nowhile();

复制代码

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
2 [报告]
发表于 2015-04-20 11:00 |只看该作者
本帖最后由 yulihua49 于 2015-04-20 12:00 编辑
sasinop 发表于 2015-04-18 10:00
大概流程就是:main.c 主文件运行后,接受客户端连接,当客户端发相应命令过来后,在tcp.c 文件中解析后, ...

这算是啥封装哦!
根据你的题目,就是要写一个函数,利用epoll进行异步操作,让应用可以使用这个函数发送任何信息,屏蔽epoll的一切特性。
为完成这个任务,可能需要一些初始化工作。
http://bbs.chinaunix.net/thread-4174032-1-2.html
看看3楼那个,才是“封装”,应用只要调用那个函数即可发送任意数据,异步操作,epoll,线程池,协程之类的细节完全屏蔽。
那是一个实际可以工作的程序,不是个demo或者作业什么的。没有给出初始化过程。

那个例子表示了什么是“封装”。怎样封装的,需要对do_event()进行逐层展开。
你的例子大量使用全局变量,无法支持多线程。

你同事的要求是对的,你要写一个通用的发送函数,供各种场合用。很可能还需要个接收函数。
你的那么多行程序没必要提供,自己留着用,只需对外提供:
初始化(构造函数),善后(析构函数),发送函数,接收函数即可。

人们不关心你的process,无数的应用逻辑,可以有无数的process,他们的共同需求是在网上收发数据。
他们希望唯一的线程(你那个是单线程的)不要耽误在等待IO上,又不希望复杂的异步逻辑把应用逻辑搅得一塌糊涂。
于是,AIO -- 协程就产生了。

你可以拿我那个程序问问同事,要的是不是这个东西,然后再说怎么做。

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
3 [报告]
发表于 2015-04-21 11:30 |只看该作者
封装性太差了,应该先将epoll细节封装起来,之后再封装tcp/udp,这样做业务才会变简单。

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
4 [报告]
发表于 2015-04-21 16:57 |只看该作者
回复 2# yulihua49

谢谢呀

没法测试你的哪个函数


不知道你那个封装的函数,是不是在一个工程里,有N多个文件时,随意在某个文件里都可以调用,都可以来发送数据给客户端?






   

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
5 [报告]
发表于 2015-04-21 17:03 |只看该作者
你同事的要求是对的,你要写一个通用的发送函数,供各种场合用。很可能还需要个接收函数。


这样好么?

一个函数比如,do (in,out) 这样, 命令和结果一个函数扎口不好在什么地方呢?

同事那种要求:do(in), 只进命令,,结果 send(out),要在不同的文件,不同的命令分支调用,处理完成后,就直接把结果送出去了... 难道这样好?

不解,请赐教呀

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
6 [报告]
发表于 2015-04-21 20:23 |只看该作者
sasinop 发表于 2015-04-21 16:57
回复 2# yulihua49

谢谢呀

那个函数仅供学习,它是交易中间件的一部分,整个系统太大了,要下载整个中间件的源码。
你用那个函数,看懂过程和概念即可,按这个思路写自己的东西。

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
7 [报告]
发表于 2015-04-21 20:26 |只看该作者
本帖最后由 yulihua49 于 2015-04-21 20:53 编辑
sasinop 发表于 2015-04-21 17:03
这样好么?

一个函数比如,do (in,out) 这样, 命令和结果一个函数扎口不好在什么地方呢?

in和out还是要分开的,比如有时是一进一出,有时是几进一出,一进几出,只进不出。。。。
还有,正常出,错误(异常)出等等,业务逻辑什么需求都有。

所以,你只要提供 in,out就可以了,何时in,何时out,它们之前,之间,之后做了什么你就不必管了。

就像我那个程序,只管发送N字节到socket。之前,要填充包头,包体要压缩,加密,校验。。。
之后要归还资源(内存和连接池),写日志。。。。。。这些你管的着吗?

你写了个in,out,把AIO,epoll...都埋藏在这两个函数里,外边那些作业就容易多了。
看我的程序,知道怎么埋藏,这可是个大学问。

对了,那个windoze也很会埋,我还是跟他学的。不过他的代码很多,你也可以用他的那个fiberized .IO, C++  的。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP