Linux平台epoll模式高级网络应用

一、实验目的和任务

  1. 本实验要求复习ubuntu的IP配置知识。
  2. 复习使用socket编程的基本方法。
  3. 学习epoll服务模式的基本用法。
    二、实验设备介绍
    1.软件需求: win7操作系统,VMware workstation,ubuntu12 [配置交叉编译环境]。
    2.硬件需求: PC内存大于1G,硬盘空间大于20G;smart210开发板。
    三、注意事项和要求
    1.启动虚拟机配置IP地址。
    2.注意启动多个客户端与服务端进行通信。
    3.程序运行结果截图后放入实验报告中。
    四、实验内容和步骤
    epoll模式下操作系统负责保存监视对象文件描述符,epoll_wait函数等待文件描述符的变化,并且epoll方式将发生变化的文件描述符专门集中在一起,这样能大大提高程序执行效率,并降低资源消耗。

4.1回声服务端程序epoll_serv.c

//037.c《TCP/IP网络编程》page 279  epoll_serv.c 对应的客户端为 echo_client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <errno.h>

#define BUF_SIZE 100
#define EPOLL_SIZE 50 
void setnonblockingmode(int fd);
void error_handling(char * message);
int main(int argc,char *argv[])
{
	int server_sock,clnt_sock;
	struct sockaddr_in serv_addr,clnt_adr;
	socklen_t adr_sz; 
	int str_len,i;
	char buf[BUF_SIZE];
	
	struct epoll_event *ep_events;
	struct epoll_event event;
	int epfd,event_cnt; 
	if(argc!=2)
	{
		printf("Usage :%s <PORT>\n",argv[0]);
		exit(1); 
	}
	server_sock=socket(PF_INET,SOCK_STREAM,0);
	if(server_sock==-1) 
		error_handling("socket() create failed."); 
	memset(&serv_addr,0,sizeof(serv_addr));
	serv_addr.sin_family=AF_INET;
	//IP地址
	serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
	//PORT
	serv_addr.sin_port=htons(atoi(argv[1]));
	if(bind(server_sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr))==-1)
		error_handling("bind() failed.");
	if(listen(server_sock,5)==-1)
		error_handling("listen() failed.");
	epfd=epoll_create(EPOLL_SIZE);
	//分配EPOLL_SIZE个epoll_event用于记录事件
	ep_events=malloc(sizeof(struct epoll_event)*EPOLL_SIZE);
	printf("ep_events=malloc(). \n");
	//设置socket为非阻塞模式
	setnonblockingmode(server_sock);
	event.events=EPOLLIN;
	event.data.fd=server_sock;
	epoll_ctl(epfd,EPOLL_CTL_ADD,server_sock,&event);  
	
	while(1)
	{
		event_cnt=epoll_wait(epfd,ep_events,EPOLL_SIZE,500);
		if(event_cnt==-1)
		{
			puts("epoll_wait() error.");
			break; 
		}
		//printf("return epoll_wait(). event_cnt=%d\n",event_cnt);
		//遍历所有ep_events对象
		for(i=0;i<event_cnt;i++)
		{
			//是监听socket对象事件则执行accept方法
			if(ep_events[i].data.fd==server_sock)
			{
				adr_sz=sizeof(clnt_adr);
				//每次accept会创建一个新socket用于数据通信
				clnt_sock=accept(server_sock,(struct sockaddr*)&clnt_adr,&adr_sz);
				printf("connected client ID=: %d \n",clnt_sock);
				//设置socket为非阻塞模式
				setnonblockingmode(clnt_sock);
				event.events=EPOLLIN|EPOLLET;
				event.data.fd=clnt_sock;
				//注册监视对象文件描述符
				epoll_ctl(epfd,EPOLL_CTL_ADD,clnt_sock,&event); 
			}else
			{//是普通socket对象则执行读操作
				str_len=read(ep_events[i].data.fd,buf,BUF_SIZE);
				if(str_len==0)
				{//收到字节长度为0,表示对方shutdown,则执行close操作
					epoll_ctl(epfd,EPOLL_CTL_DEL,ep_events[i].data.fd,NULL);
					close(ep_events[i].data.fd);
					printf("closed client:%d \n",ep_events[i].data.fd);
					break; 
				}else if(str_len<0)
				{//收到字节长度小于0
					if(errno==EAGAIN) break;
				}else
				{//收到字节度大于0,执行回复操作
					printf("Message from %d. :%s",ep_events[i].data.fd,buf);
					write(ep_events[i].data.fd,buf,str_len);
				} 
			}
		}
	} 
	close(server_sock);
	close(epfd);
	return 0;
}

void setnonblockingmode(int fd)
{
	int flag=fcntl(fd,F_GETFL,0);
	fcntl(fd,F_SETFL,flag|O_NONBLOCK);
}
//错误处理是将信息输出到标准输出,然后退出进程。
void error_handling(char * message)
{
	fputs(message,stderr);
	fputc('\n',stderr);
	exit(1); 
}

下面是epoll模式运行示意图。在这里插入图片描述

4.2回声客户端程序echo_client.c

为方便与服务端配合运行,将回声客户端程序在此列出,通过启动多个客户端实例来验证并发服务器功能。

// 053.c回声客户端《TCP/IP网络编程》page75
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> 
#include <arpa/inet.h>
#include <sys/socket.h> 
#define BUF_SIZE 1024
void error_handling(char *message);  
int main(int argc,char * argv[])
{
	int sock;
	char message[BUF_SIZE];
	int str_len;
	struct sockaddr_in serv_adr; 
	if(argc!=3)
	{
		printf("Usage : %s <IP> <port>\n",argv[0]);
		exit(1); 
	}  
	//创建TCP客户端socket文件资源
	sock=socket(PF_INET,SOCK_STREAM,0);
	if(sock==-1)
		error_handling("socket() 创建失败."); 
	memset(&serv_adr,0,sizeof(serv_adr));
	serv_adr.sin_family=AF_INET;
	serv_adr.sin_addr.s_addr=inet_addr(argv[1]);
	serv_adr.sin_port=htons(atoi(argv[2])); 
	//连接服务端
	if(connect(sock,(struct sockaddr*)&serv_adr,sizeof(serv_adr))==-1)
		error_handling("connect() failed.");
	else//连接成功
		puts("Connected success .....");
	while(1)
	{
		fputs("Input message(Q to quit):",stdout);
		fgets(message,BUF_SIZE,stdin);
		if(!strcmp(message,"q\n")||!strcmp(message,"Q\n"))
			break;//收到q字符则退出
		write(sock,message,strlen(message));
		str_len=read(sock,message,BUF_SIZE-1);
		message[str_len]=0;
		printf("Message from server: %s",message);
	} 
	close(sock);
	return 0; 
}  
//错误处理是将信息输出到标准输出,然后退出进程。
void error_handling(char * message)
{
	fputs(message,stderr);
	fputc('\n',stderr);
	exit(1); 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值