linux Epoll 发送函数的封装问题…

C语言 码拜 9年前 (2015-05-11) 964次浏览 0个评论
 

大概流程就是:main.c 主文件运行后,接受客户端连接,当客户端发相应命令过来后,在tcp.c 文件中解析后,调用function.c文件中的处理函数:Receive_Process()。
原来我的想法是,在function处理完成后,通过Receive_Process()函数再把结果返回,

void Receive_Process(int conn_fd,unsigned char*  buff_r,unsigned char*  buff_w)

如果这样的话,就没这些问题了,处理的结果,我在tcp.c文件中,通过 “unsigned char*  buff_w” 可以拿到,送给PC就完事了。

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

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

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

#include "tcp.h"
int main(int argc, char * argv[])   
{
 		tcp_initialize(); 
		epoll_fd_tcp=create_epoll_tcp(MAX_EVENTS_TCP);	 
	  while(1)
	  {
	  	 do_process_tcp_nowhile();
	  	 sleep(1);
	  }	 
}  

处理文件:function.c

#include "function.h"

void Receive_Process(int conn_fd,unsigned char*  buff_r,unsigned char*  buff_w)
{
	unsigned char CmdKey;
	unsigned char length;
	int len,i;
  len = buff_r[1];
	CmdKey = buff_r[2];
	printf("packet len is : %02X\n",buff_r[1]);
	printf("cmdkey is : %02X\n",buff_r[2]);
	for(i=0;i<len;i++)
     		buff_r[i]=buff_r[i+1];
     	for(i=0;i<len;i++)
     		printf("%02X ",buff_r[i]);
  printf("\n");
switch(CmdKey)
	{
		case 0x02:
			//write_spi_arm_to_fpga_array(5,buff_r,buff_w);
                       // 根据命令,与FPGA交互后,将返回结果送给PC端,下面是模拟的数据。
			buff_w[0]=0x08;
			buff_w[1]=0x03;
			buff_w[2]=0x8c;
			buff_w[3]=0x00;
			buff_w[4]=0x00;
			//send to pc
                        tcp_send_data_to_pc(5 buff_w);
                       // 无发完成发送任务,这个函数只能在tcp.c文件中能正常,出了tcp.c文件就不行了。
			printf("CMD_GET_VERSION OK \n");
			break;
		default:
			break;
	}
}

TCP文件: tcp.c

#include "tcp.h"

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


int server_sock_fd_tcp;// 服务器端套接字   
int client_sock_fd_tcp;// 客户端套接字      
int nfds_tcp;// epoll监听事件发生的个数 
int len_recv_data_tcp;
struct sockaddr_in host_addr_tcp;   // 服务器网络地址结构体   
struct sockaddr_in remote_addr_tcp; // 客户端网络地址结构体   
int sin_size;   
unsigned char send_data_buffer_size_tcp[BUFFER_SIZE_TCP];  // 数据传送的缓冲区  
unsigned char retn_data_buffer_size_tcp[BUFFER_SIZE_TCP];    
int m=0;
int len;
//设置句柄为非阻塞方式 
int setnonblocking(int sockfd)  
{  
 if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK) == -1)  
 {  
    return -1;  
 }  
    return 0;  
} 

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

void tcp_initialize()
 { 
    struct rlimit rt;
    
    /* 设置每个进程允许打开的最大文件数 */  
    rt.rlim_max = rt.rlim_cur = 1024;  
    if (setrlimit(RLIMIT_NOFILE, &rt) == -1)   
		{  
        perror("setrlimit");  
        exit(1);  
    }  
    else   
    {  
        printf("setrlimit ok! \n");  
    }  
    
    // 创建服务器端套接字--IPv4协议,面向连接通信,TCP协议
    if((server_sock_fd_tcp=socket(PF_INET,SOCK_STREAM,0))<0)   
    {     
        perror("socket");   
        //return 1;   
    }
    else
    {
    	printf("Tcp server socket ok...\n"); 
    }
    
    	// 设置 socket属性,端口可以重用   
  
  	int opt=SO_REUSEADDR;
  	setsockopt(server_sock_fd_tcp,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
  	setnonblocking(server_sock_fd_tcp);
    
    memset(&host_addr_tcp,0,sizeof(host_addr_tcp)); // 数据初始化--清零      
    host_addr_tcp.sin_family=PF_INET; // 设置为IP通信   
    host_addr_tcp.sin_addr.s_addr=inet_addr(HOST_IP_ADDRESS_TCP);// 服务器IP地址--允许连接到所有本地地址上   
    host_addr_tcp.sin_port=htons(HOST_PORT_TCP); // 服务器端口号  
    
    // 将套接字绑定到服务器的网络地址上
    if (bind(server_sock_fd_tcp,(struct sockaddr *)&host_addr_tcp,sizeof(struct sockaddr))<0)   
    {   
        perror("bind");   
        //return 1;   
    }
    else
    {
    	printf("Tcp server bind ok...\n"); 
    	printf("IP  : %s   \n", inet_ntoa(host_addr_tcp.sin_addr));
    	printf("port: %d \n",ntohs(host_addr_tcp.sin_port));
    }
    // 监听连接请求--监听队列长度为5 
    listen(server_sock_fd_tcp,64);   
    sin_size=sizeof(struct sockaddr_in); 
 
}
 
 // 创建一个epoll句柄
int create_epoll_tcp(unsigned int event_num)
  {
  	int epoll_fd;
		epoll_fd=epoll_create(event_num);
		if(epoll_fd==-1)
		{
			perror("epoll_create failed");
		}
		ev.events=EPOLLIN | EPOLLET;
		ev.data.fd=server_sock_fd_tcp;
		// 向epoll注册server_sockfd监听事件
		if(epoll_ctl(epoll_fd,EPOLL_CTL_ADD,server_sock_fd_tcp,&ev)==-1)
		{
			perror("epll_ctl:server_sock_fd_tcp register failed");
		}
		else
  	{
    	printf("socket adding in  epoll success! \n");
  	}
		return epoll_fd;
} 
 
void do_process_tcp_nowhile()
{  
			// 等待事件发生
			nfds_tcp=epoll_wait(epoll_fd_tcp,events,1024,-1);
			if(nfds_tcp==-1)
			{
				perror("start epoll_wait failed");
				//exit(EXIT_FAILURE);
			}
			else
			{
					printf(" epoll nfds_tcp = %d   \n",nfds_tcp);
			}

			for(n=0;n<nfds_tcp;++n)
			{
				printf(" for loop epoll nfds_tcp = %d   \n",nfds_tcp);
				// 客户端有新的连接请求
				if(events[n].data.fd == server_sock_fd_tcp)
				{
					// 等待客户端连接请求到达
		      if((client_sock_fd_tcp=accept(server_sock_fd_tcp,(struct sockaddr *)&remote_addr_tcp,&sin_size))<0)
					{   
						perror("accept client_sock_fd_tcp failed");   
						exit(EXIT_FAILURE);
					}
					// 向epoll注册client_sockfd监听事件
					setnonblocking(client_sock_fd_tcp);
					ev.events=EPOLLIN | EPOLLET;
					ev.data.fd=client_sock_fd_tcp;
					if(epoll_ctl(epoll_fd_tcp,EPOLL_CTL_ADD,client_sock_fd_tcp,&ev)==-1)
					{
						perror("epoll_ctl:client_sock_fd_tcp register failed");
					}
					printf("accept client %s\n",inet_ntoa(remote_addr_tcp.sin_addr));
				}
				else if(events[n].events & EPOLLIN)
				{
					// 客户端有数据发送过来
					sprintf(send_data_buffer_size_tcp,"");
					//sin_size=sizeof(remote_addr_tcp);

					len_recv_data_tcp=recv(events[n].data.fd,send_data_buffer_size_tcp,BUFFER_SIZE_TCP,0);
					if(len_recv_data_tcp<=0)
					{
						printf("close id is : %d \n",events[n].data.fd);
						if(epoll_ctl(epoll_fd_tcp,EPOLL_CTL_DEL,events[n].data.fd,&ev)==0)
						{
							printf("delete ok \n");
							close(events[n].data.fd); 
						}
						else
						{
							printf("delete error \n");
						}
					}
					else
					{//处理PC来的命令包,,调用fuction.c文件中的 Receive_Process()函数
		     		Receive_Process(4,send_data_buffer_size_tcp,retn_data_buffer_size_tcp);
		     
						ev.data.fd = events[n].data.fd;
            ev.events = EPOLLOUT|EPOLLET;
            epoll_ctl(epoll_fd_tcp, EPOLL_CTL_MOD, events[n].data.fd, &ev);
					}
				}
				else if(events[n].events & EPOLLOUT)//发送
				{
					tcp_send_data_to_pc(4,send_data_buffer_size_tcp);	//这个地方就正常	
				}
			}

		if(server_sock_fd_tcp>0)
		{
			printf("socket close \n");
			shutdown(server_sock_fd_tcp,SHUT_RDWR);
			close(server_sock_fd_tcp);
		}

}

tcp.h头文件

#include <arpa/inet.h>  
#include <fcntl.h>  
#include <sys/epoll.h>  
#include <sys/time.h>  
#include <sys/resource.h>  

#define BUFFER_SIZE_TCP 40
#define MAX_EVENTS_TCP 10
#define HOST_IP_ADDRESS_TCP "192.168.1.200"
#define HOST_PORT_TCP 4530

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

int epoll_fd_tcp;
int tcp_send_data_to_pc(int len,char* buffer);
void tcp_initialize();
int create_epoll_tcp(unsigned int event_num);
void do_process_tcp_nowhile();

来个人顶一下呀

也好结贴 呢

结贴,还能赚个50 嘿嘿

10分
好奇为何不直接用libevent呢?
90分
实现不好意思回这个贴了

上两次回贴都没帮到你。

发送数据跟 epoll 是没有关系的.  都可以直接 write(fd ,….) 

Receive_Process(4,send_data_buffer_size_tcp …)
write(events[n].data.fd, send_data_buffer_size_tcp, 4);   // 直接发

下面的  所有关于EPOLLOUT 事件注册和处理都不要了

// —————————————
楼主是不是看了百度百科那份epoll 资料呀!?那份资料有点坑爹

引用 3 楼 dooX8086 的回复:

实现不好意思回这个贴了

上两次回贴都没帮到你。

发送数据跟 epoll 是没有关系的.  都可以直接 write(fd ,….) 

Receive_Process(4,send_data_buffer_size_tcp …)
write(events[n].data.fd, send_data_buffer_size_tcp, 4);   // 直接发

下面的  所有关于EPOLLOUT 事件注册和处理都不要了

// —————————————
楼主是不是看了百度百科那份epoll 资料呀!?那份资料有点坑爹

上次帮到了 呵呵


CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明linux Epoll 发送函数的封装问题…
喜欢 (0)
[1034331897@qq.com]
分享 (0)

文章评论已关闭!