epoll服務器代碼實例

/*該文件實現服務器的監聽
 *
 *
 * 
 */
#include<stdio.h>
#include<sys/epoll.h>
#include<sys/socket.h>
#include<errno.h>
#include<string.h>
#include<iostream>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<stdlib.h>
#include<fcntl.h>
#include<list>
using namespace std;
const int maxn = 1e2+10;
int port=80;
char host[maxn]="localhost";
list<int> clientList;
void setAddr(struct sockaddr_in &addr,char *host,int port){
	addr.sin_family=AF_INET;
	addr.sin_port=htons(port); //轉換成網絡序(大端)
	addr.sin_addr.s_addr=inet_addr("127.0.0.1");
}
void perr(const char *s){
	perror(s);
	exit(-1);
}
void setnonblocking(int sockfd){
	fcntl(sockfd,F_SETFL,fcntl(sockfd,F_GETFD,0)|O_NONBLOCK);
	return;
}
int sendBroadMessage(int nowfd){ //收到信息先接收信息 ,然後再發給list裏面的所有
	char message[1024];
	bzero(message,sizeof(message));
	int len=recv(nowfd,message,1024,0);
	if(len==0){ //客戶端關閉了鏈接
		close(nowfd);
		clientList.remove(nowfd);
		printf("關閉了一個鏈接");
	}
	else{
		list<int>::iterator it;
		int cnt=0;
		for(it=clientList.begin();it!=clientList.end();it++){
			if(send(*it,message,1024,0)<0){
				printf("%d\n",*it);
				perror("send error");
			} 
			else{
				printf("%d\n發送成功",*it);
			}
		}
	}
	return len;
}
void addfd(int epollfd,int fd,bool flag){// flag用來設置水平還是垂直
	struct epoll_event ev;
	ev.data.fd=fd;
	ev.events=EPOLLIN;
	if(flag){ //設置水平觸發
		ev.events|=EPOLLET;
	}
	epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,&ev);
	setnonblocking(fd);
	printf("fd added to epoll!\n\n"); 
	return;

}
int main(){
	int sta=0;
	int sock=socket(AF_INET,SOCK_STREAM,0);
	if(sock<0) perr("socket出錯");
	struct sockaddr_in serverAddr,clientAddr;
	bzero(&serverAddr,sizeof(serverAddr));
	bzero(&clientAddr,sizeof(clientAddr));
	setAddr(serverAddr,host,port);
	//	sta=listen(sock,5);
	//	if(sta<0) perr("listen");
	if(bind(sock,(struct sockaddr*)&serverAddr,sizeof(serverAddr))<0) perr("bind");	
	sta=listen(sock,5);
	if(sta<0) perr("listen");	
	socklen_t addrLength = sizeof(struct sockaddr_in);


	static struct epoll_event events[1024];

	int epfd=epoll_create(1); //這個參數大於0就行,沒啥用
	addfd(epfd,sock,true);
	while(true){
		int epollEventCnt=epoll_wait(epfd,events,1024,-1);
		//這裏感覺不應該設置成阻塞
		if(epollEventCnt<0) perr("epollWait");
		printf("epollCnt:%d\n",epollEventCnt);
		for(int i=0;i<epollEventCnt;i++){
			int now=events[i].data.fd;
			if(now==sock){ //監聽的得到了信息
				struct sockaddr_in cli;
				socklen_t cliLen=sizeof(cli);
				int newfd=accept(sock,(struct sockaddr*)&cli,&cliLen);
				printf("From:%s:%d\n",inet_ntoa(cli.sin_addr),ntohs(cli.sin_port));				
				addfd(epfd,newfd,true); //這裏服務器只設置讀入權限
				clientList.push_back(newfd);
				printf("%d描述符添加\n",newfd);
				char message[1024]="Welcome to tellHouse!\n";
				sta=send(newfd,message,1024,0);
				if(sta<0) perr("send error");
			}
			else{
				//別的鏈接來消息了,這個消息要發給所有的鏈接。
				sta=sendBroadMessage(now);
				if(sta<0) perr("運行出錯");
			}
		}
	}	
	close(epfd);
	close(sock);
	return 0;



}

  不過這個代碼還沒測試(服務器端口號沒弄好),後續會有客戶端實時通信代碼。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章