1. 程式人生 > >Linux 高效能伺服器程式設計——I/O複用 poll

Linux 高效能伺服器程式設計——I/O複用 poll

一:poll系統呼叫

  同select相似,也是在指定時間內輪詢一定數量的檔案描述符,以測試其中是否有就緒者。

二:poll函式

  1.函式原型:

#include<poll.h>

int poll(struct pollfd* fds,nfds_t nfds,int timeout);

  2.函式引數:

    先來了解一下struct pollfd這個結構體

 

struct pollfd
{
    int fd;            //檔案描述符
    short events;      //註冊的事件
    short revents;     //實際發生的事件,由核心填充。
}
/*其中fd成員指定檔案描述符;events成員告訴poll監聽fa上的那些事件,它是一系列事件的按位或;
  revents則有核心修改,以通知應用程式fd上實際發生了那些事件。*/
①fds: pollfd結構型別的陣列,指定我們所有感興趣的檔案描述符上發生的可讀,可寫,異常等事件。
②ndfs: 指定被監聽事件集合fds的大小。(其型別位:typedef unsigned long int nfds_t;)
③timeout:

設定超時時間,單位毫秒。

-1:poll將永遠阻塞

0:poll呼叫將立即返回。

三:邏輯思想

四:測試程式碼

 

伺服器端:

//poll.c
#define _GNU_SOURCE
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<assert.h>
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<poll.h>

#define SIZE 100
void Delete_fd(struct pollfd *fds , int fd)
{		
		int i=0;
		for(;i<SIZE;++i)
		{
				if(fds[i].fd == fd)
				{
						fds[i].fd = -1;
						fds[i].events = 0;
				//		fds[i].revents = 0;
				}
		}
}
void Init_fd(struct pollfd *fds)
{
		int i = 0;
		for(;i<SIZE;++i)
		{
				fds[i].fd = -1;
				fds[i].events = 0;
				fds[i].revents = 0;
		}
}
void Insert_fd(struct pollfd *fds,int fd,short event)
{
		int i= 0 ;
		for(;i<SIZE;++i)
		{
				if(fds[i].fd == -1)
				{
					fds[i].fd = fd;
					fds[i].events = event;
					break;
				}
		}
}
		
int main()
{
		int sockfd = socket(AF_INET,SOCK_STREAM,0);
		assert(sockfd != -1);

		struct sockaddr_in ser,cli;
		memset(&ser,0,sizeof(ser));

		ser.sin_family = AF_INET;
		ser.sin_port = htons(6000);
		ser.sin_addr.s_addr = inet_addr("127.0.0.1");

		int res = bind(sockfd,(struct sockaddr*)&ser,sizeof(ser));
		assert(res != -1);

		listen(sockfd,5);

		struct pollfd fds[SIZE];
		Init_fd(fds);
		Insert_fd(fds,sockfd,POLLIN);

		while(1)
		{
				int n = poll(fds,SIZE,-1);
				if(n<=0)
				{
						printf("poll fail!!!\n");
						continue;
				}
				int i = 0;
				for(;i<SIZE;++i)
				{
						if(fds[i].fd != -1)
						{
								int fd = fds[i].fd;

								if(fds[i].revents & POLLRDHUP)//這個應該放到前面
								{
										close(fd);
										Delete_fd(fds,fd);
										printf("%d: will close\n",fd);
								}
								else if(fds[i].revents & POLLIN)
								{
										if(fd == sockfd)
										{
												int len = sizeof(cli);
												int c = accept(sockfd,(struct sockaddr*)&cli,&len);
												if(c<=0)
												{
														printf("accept is fail\n");
														continue;
												}
												
												Insert_fd(fds,c,POLLIN|POLLRDHUP);
												
										}
										else
										{
												char buff[128]={0};
												int n =recv(fds[i].fd,buff,127,0);
												if(n<=0)
												{
														close(fds[i].fd);
														Delete_fd(fds,fds[i].fd);
														printf("%d: is close\n",fd);
												}
												else
												{
														printf("%d: %s\n",fd,buff);
														send(fd,"OK",2,0);
												}

										}
								}
						}
				}

		}

	close(sockfd);

}

客戶端:

#include"../../apue.h"
int main()
{
		int sockfd = socket(AF_INET,SOCK_STREAM,0);
		assert(sockfd != -1);
		struct sockaddr_in ser;
		memset(&ser,0,sizeof(ser));

		ser.sin_family = AF_INET;
		ser.sin_port = htons(6000);
		ser.sin_addr.s_addr = inet_addr("127.0.0.1");

		int res = connect(sockfd,(struct sockaddr*)&ser,sizeof(ser));
		assert(res != -1);
		
		while(1)
		{
				printf("please input:\n");
				fflush(stdout);

				char buf[128]={0};
				fgets(buf,127,stdin);
				buf[strlen(buf)-1] = 0;

				if(strcmp(buf,"end") == 0)
				{
						break;
				}
				send(sockfd,buf,strlen(buf),0);
				printf("send is OK\n");

			//	char recvbuff[128] = {0};
			//	recv(sockfd,recvbuff,127,0);
			//	printf("%s:\n",recvbuff);
		}
		close(sockfd);
}