tcp 通过poll实现socket 回射服务器

poll()函数:这个函数是某些Unix系统提供的用于执行与select()函数同等功能的函数,下面是这个函数的声明:

struct pollfd {
int fd;        /* 文件描述符 */
short events; /* 等待的事件 */
short revents; /* 实际发生了的事件 */
};

#include <poll.h>

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

参数说明:

fds:是一个struct pollfd结构类型的数组,用于存放需要检测其状态的Socket描述符;每当调用这个函数之后,系统不会清空这个数组,操作起来比较方便;特别是对于 socket连接比较多的情况下,在一定程度上可以提高处理的效率;这一点与select()函数不同,调用select()函数之后,select() 函数会清空它所检测的socket描述符集合,导致每次调用select()之前都必须把socket描述符重新加入到待检测的集合中;因 此,select()函数适合于只检测一个socket描述符的情况,而poll()函数适合于大量socket描述符的情况;

nfds:nfds_t类型的参数,用于标记数组fds中的结构体元素的总数量;

timeout:是poll函数调用阻塞的时间,单位:毫秒;

#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>
#include<stdlib.h>
#include<errno.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
#include<signal.h>
#include<sys/wait.h>
#include<poll.h>  
#include<sys/stropts.h>

#define MAXLINE 1024
#define OPEN_MAX  128 
#define ERR_EXIT(m)     do {  perror(m);   exit(EXIT_FAILURE); } while (0)

int main(int argc, char **argv)
{
	int listenfd, connfd, sockfd;
	int i, maxi, nready;
	ssize_t n;
	char buf[MAXLINE];
	socklen_t clilen;
	struct pollfd client[OPEN_MAX];
	struct sockaddr_in cliaddr, servadd;

	if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
	{
		ERR_EXIT("socket error");
	}

	memset(&servadd, 0, sizeof(servadd));

	servadd.sin_family = AF_INET;
	servadd.sin_port = htons(49160);
	servadd.sin_addr.s_addr = htonl(INADDR_ANY);
	//if((inet_pton(AF_INET, "127.0.0.1", &servadd.sin_addr))<0)
	//	ERR_EXIT("inet_pton error");

	if (bind(listenfd, (struct sockaddr *)&servadd, sizeof(servadd))<0)
	{
		ERR_EXIT("bind error");
	}

	if (listen(listenfd, SOMAXCONN) < 0)
	{
		ERR_EXIT("listen error");
	}

    client[0].fd = listenfd;
    client[0].events = POLLRDNORM;
    for (i = 1; i < OPEN_MAX; ++i)
    {
    	client[i].fd = -1;
    }
    maxi = 0;
    for ( ; ; ){
    	//内核监听事件,如果有就绪事件立马返回
    	//INFTIM没有定义,直接写成-1即可
    	printf("阻塞到poll#########\n");
    	nready = poll(client, maxi+1,-1);
    	//该if条件代表监听client的接入
    	if (client[0].revents & POLLRDNORM){
    		clilen = sizeof(cliaddr);
    		connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);
    		for (i = 1; i < OPEN_MAX; ++i){
    			if (client[i].fd < 0){
    				client[i].fd = connfd; //保存已经连接的描述符
    				break;
    			}
    		}
    		if (i == OPEN_MAX){
    			ERR_EXIT("too many clients");
    		}

    		client[i].events = POLLRDNORM;
    		if (i>maxi){
    			maxi = i;
    		}
    		printf("###nread:%d\n", nready);
    		if (--nready <= 0){
    			printf("继续监听连接描述符的事件\n");
    			continue; //继续监听连接描述符的事件.
    		}
    	}
    	printf("检查nready事件:%d,maxi:%d\n", nready,maxi);
		//检查所有的clients 数据的写入
		for (i = 1; i <= maxi; ++i){
			if((sockfd = client[i].fd) < 0){
				continue;//继续坚持可用的client描述符
			}
			//内核通过revents返回描述符的状态给应用(client端往server端写入了数据)
			if (client[i].revents &(POLLRDNORM | POLLERR)){
				//每次read 必须把buf重新清零,不然缓存中原有的旧数据
				//会被重新写入到client端
				memset(buf, 0, sizeof(buf));
				if ((n = read(sockfd, buf, MAXLINE))<0){
					if (errno == ECONNRESET)
					{
						//connnection reset by client
						printf("connection reset by client\n");
						close(sockfd);
						client[i].fd = -1;
					}else{
						printf("read error\n");
					}
				}else if (n == 0){
					//connection closed by client
					printf("connection closed by client\n");
					close(sockfd);
					client[i].fd = -1;
				}else{
					printf("send data to client,data: %s\n", buf);
					write(sockfd,buf,n);
				}

				if (--nready <=0 ){
					break;
				}
			}
		}
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值