select和poll服務器實現(Linux)

select是一個系統調用和應用程序編程接口(API)在類Unix和POSIX兼容的操作系統用於檢查的狀態文件描述符打開輸入/輸出通道。選擇系統調用是類似的調查在UNIX System V和更高版本的操作系統推出設施.

函數如下:

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout);


fd_set type參數可以具有四個工具宏來處理:FD_SET(),FD_CLR(),FD_ZERO() ,和FD_ISSET() 。(這裏便不細說了,有疑問的讀者可以man)

選擇回報位設置總數readfds,writefds和errorfds,或零如果超時到期,-1。

文件描述符在選擇所使用的集合是有限的大小,取決於操作系統。較新的系統調用輪詢提供了更靈活的解決方案。


select服務器代碼如下

<span style="font-size:18px;">#include<stdio.h>
#include<sys/socket.h>
#include<errno.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<sys/time.h>

char fds[128];
#define COUNT   sizeof(fds)/sizeof(fds[0])
   int max_fd = 0;

static void guse(const char* prac)
{
printf("%s [ip] [port]..\n",prac);
}

static int my_select(const char* _ip, const int _port){
	int sock = socket(AF_INET,SOCK_STREAM,0);
	if(sock < 0){
		perror("create socket error...");
		exit(1);

	}
	
	struct sockaddr_in server_socket;
	bzero(&server_socket,sizeof(server_socket));
	server_socket.sin_family = AF_INET;
	server_socket.sin_addr.s_addr =inet_addr(_ip);
	server_socket.sin_port = htons(_port);
	
	int opt = 1;
	setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
	
	if(bind(sock,(struct sockaddr*)&server_socket,sizeof(server_socket))< 0)
	{
		perror("bind error ...");
		exit(2);
	}
	
	if(listen(sock,5) < 0 ){
		perror("listen errno ...");
		close(sock);
		 exit(3);
	}

	return sock;
}

static void init_fd_arr()
{

   int i = 0;
   for(;i<COUNT;i++){
	   fds[i] = -1;
   }
}

static int add_fd_arr(int fd){

   int i = 0;
   for(;i<COUNT;i++){
	   if(fds[i] == -1){
		   fds[i] = fd;
		   return 0;
	   }
   }
   return i;
}

static int remove_arr(int fd){
	int i = 0;
	for(; i < COUNT; i++){
		if(fds[i] == fd){
			fds[i] = -1;
			break;
		}
	}
	return 0;
}

static int setifd(fd_set * fdset){
	int i = 0;
	for(;i<COUNT;i++){
		if(fds[i] != -1 ){
			FD_SET(fds[i],fdset);
			if(fds[i]>max_fd)
				max_fd = fds[i];
		}
	}
	return 0;
}

int main(int argc,char* argv[])
{
   if(argc != 3)
 {
   guse(argv[0]);
     exit(0);
 }
   init_fd_arr();
   int listen_sock =  my_select(argv[1], atoi(argv[2]));
   add_fd_arr(listen_sock);
   fd_set red;
    FD_ZERO(&red);
   while(1){
       setifd(&red);
	   FD_SET(listen_sock,&red);
        struct timeval _timeout ={5,0};
		switch(select(max_fd+1,&red,NULL,NULL,&_timeout)){
			case -1:
				printf("selsect errno..\n");
				exit(4);
				break;
			case 0:
				printf("Time out \n");
				break;
			default:
				{
					int index = 0;
					for(;index < COUNT; index++){
						if(fds[index] != -1 && FD_ISSET(fds[index],&red)){

	            struct sockaddr_in peer;
				int addrlen = sizeof(peer);
				int ret = accept(listen_sock,(struct sockaddr*)&peer,&addrlen);
				if(ret  < 0){
					perror("accept error...\n");
					close(ret);
					exit(4);
						}else
						{
							if(1 == add_fd_arr(ret)){
								printf("full ...\n");
									close(ret);
							}
						}
                printf("Yougot a connection from cient's ip is %s, prot is %d\n",inet_ntoa(peer.sin_addr),htons(peer.sin_port));
				continue;
					}
				}
					if(fds[index] != -1 && FD_ISSET(fds[index],&red)){

				char buf[1024];
                memset(buf,'\0',sizeof(buf));
				ssize_t _s = read(fds[index],buf,sizeof(buf)-1);
				if(_s == 0){
					printf("client close ...\n");
				}
				else if(_s < 0)
				{
					printf("errno  read..\n");
				}
				else{
					printf("server:%s",buf);
				}
					}


				}
				break;
		}
   }

return 0;
}
</span>

首先我們來看看這個這個程序的結果:


可以看出,這個程序跟上一篇TCP服務器的功能是一樣的。至於客戶端,讀者可以去看上一篇博文,這篇文章便不再敘說。



poll:



<span style="font-size:18px;">#include<stdio.h>
#include<poll.h>
#include<errno.h>
#include<string.h>
#include<stdlib.h>

int main()
{
	struct pollfd polls[1];
	polls[0].fd = 0;
	polls[0].events = POLLIN;
	polls[0].revents = 1;
	int times = 5000;

	char buf[1024];
	while(1)
	{
	switch(poll(polls,1,times)){
		case -1:
			printf("poll error...\n");
			exit(0);
			break;
		case 0:
			printf("Time OUT ...\n");
			break;
		default:
			{
				memset(buf,'\0',sizeof(buf));
			    read(1,buf,sizeof(buf));
				printf("%s\n",buf);
				
				
			}
			break;

	}
	}
	return 0;
}
</span>

這個程序的功能是你輸入一個字符,然後服務器給你返回那個值:





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