多路转接服务器之poll

来源:互联网 发布:端口费用是什么意思 编辑:程序博客网 时间:2024/05/21 21:36

多路转接server之poll模型

poll函数原型:

#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);

包含于poll.h头文件中

  • fds是一个pollfd结构体类型的一个数组,里面存放我们关心的文件描述符中的读、写和异常事件。 
    pollfd结构体类型定义:

    struct pollfd {
    int fd; /* file descriptor */
    short events; /* 所关心的事件 */
    short revents; /* 实际发生的事件,由内核返回给user */
    };
    常见的events有POLLIN,POLLOUT,POLLERR等。
    revents返回实际已就绪的事件。
  • nfds 指定被监听事件集合fds的大小,定义如下:

    typedef unsigned long int nfds_t
  • timeout poll的超时值,单位为ms(毫秒),当为-1时表示永远阻塞,知道某个事件发生,为0时表示只要调用poll则立即返回。

poll和select的返回值表示的意义一样,poll较select改进的地方就是poll使用了读写分离,即设置了一个输入型参数(events告诉内核所关心的事件)和一个输出型参数(revents内核告诉用户哪些事件已就绪),而且它的文件描述符的数量不再被限制(因为使用了数组)

poll_server

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<poll.h>
#include<netinet/in.h>
#include<string.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<sys/select.h>

#define SIZE 1024

static void usage(char* proc)// 用户手册
{
printf("Usage :%s [local_ip] [local_port]\n",proc);
}
int startup(const char *ip, int port)// 创建监听套接字
{
int sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0){
perror("socket");
exit(2);
}
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = inet_addr(ip);
if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0){
perror("bind");
exit(3);
}
if(listen(sock, 10) < 0){
perror("listen");
exit(4);
}
return sock;
}

int main(int argc, char *argv[])
{
if(argc != 3){
usage(argv[0]);
return 1
}
int listen_sock = startup(argv[1], atoi(argv[2]));
struct pollfd ev[SIZE];// 创建一个pollfd结构体类型的数组
memset(ev, 0, sizeof(ev));// 对数组初始化
// 把listen_sock设置进数组
ev[0].fd = listen_sock;
ev[0].events = POLLIN;
int count = 1;
while(1){
switch(poll(ev, count, -1))
{
case -1:
perror("poll");
break;
case 0:
printf("timeout!...\n");
break;
default:
{
int i = 0;
for(i=0; i < count; i++){
if(i == 0 && (ev[i].revents & POLLIN )){
struct sockaddr_in client;
socklen_t len = sizeof(client);
int client_sock = accept(listen_sock, (struct sockaddr*)&client, &len);
if(client_sock < 0){
perror("accept");
continue;
}
//把就绪的文件描述符添加进fds数组
printf("get a client \n",inet_ntoa(client.sin_addr), ntohs(client.sin_port));
ev[count].fd = client_sock;
ev[count].events = POLLIN;
count++;
ev[i].revents = 0;
}else if(ev[i].events & POLLIN){
char buf[512];
ssize_t s = read(ev[i].fd, buf, sizeof(buf)-1);
if(s > 0){
buf[s-1] = 0;
printf("client say# %s\n", buf);
write(ev[i].fd, buf, strlen(buf));
}else if(s == 0){
printf("client quit!!!\n");
close(ev[i].fd);
ev[i].fd=0;
ev[i].events=0;
}else{
perror("read");
close(ev[i].fd);
ev[i].fd=0;
ev[i].events=0;
}
}else{ }
}
}
break;
};
}
return 0;
}
原创粉丝点击