day3 多路复用poll函数

poll函数

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

 参数:

结构体pollfd:

struct pollfd{
    int fd;        //文件描述符;
    short events;  //请求的事件;
    short revents; // 返回的事件;
};

poll函数:事件类型

events:

POLLIN:有数据可读

POLLPRI:有紧急数据需要读取

POLLOUT: 文件可写

.....

nfds : fds的个数;

timeout:

        1、设置阻塞的事件(毫秒);

        2、0为非阻塞;

        3、负数为永久阻塞;
 

epoll函数族

/*创建epoll句柄*/
int epoll_create(int size);  //size参数实际上已经被弃用

/*epoll句柄的控制接口*/
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

/*等待 epoll 文件描述符上的 I/O 事件*/
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

epfd: epoll 专用的文件描述符,epoll_create()的返回值

op: 表示动作,用三个宏来表示:

         EPOLL_CTL_ADD:注册新的 fd 到 epfd 中;

         EPOLL_CTL_MOD:修改已经注册的fd的监听事件;

         EPOLL_CTL_DEL:从 epfd 中删除一个 fd;

fd: 需要监听的文件描述符

event: 告诉内核要监听什么事件
 

poll的实现

net.h

#ifndef _NET_H_
#define _NET_H_

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

typedef struct sockaddr Addr;
typedef struct sockaddr_in Addr_in;
#define BACKLOG 5
#define ErrExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while(0)

void Argment(int argc, char *argv[]);
int CreateSocket(char *argv[]);
int DataHandle(int fd);


#endif

server.c

#include "net.h"
#include 

#define MAX_SOCK_FD 1024
int main(int argc, char *argv[])
{
	int i, j, fd, newfd;
	nfds_t nfds = 1;
	struct pollfd fds[MAX_SOCK_FD] = {};
	Addr_in addr;
	socklen_t addrlen = sizeof(Addr_in);
	/*检查参数,小于3个 直接退出进程*/
	Argment(argc, argv);
	/*创建已设置监听模式的套接字*/
	fd = CreateSocket(argv);
	fds[0].fd = fd;
	fds[0].events = POLLIN;
	while(1){
		if( poll(fds, nfds, -1) < 0)
			ErrExit("poll");
		for(i = 0; i < nfds; i++){
			/*接收客户端连接,并生成新的文件描述符*/
			if(fds[i].fd == fd && fds[i].revents & POLLIN){
				if( (newfd = accept(fd, (Addr *)&addr, &addrlen) ) < 0)
					perror("accept");
				fds[nfds].fd = newfd;
				fds[nfds++].events = POLLIN;
				printf("[%s:%d][nfds=%lu] connection successful.\n", 
						inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), nfds);
			}
			/*处理客户端数据*/
			if(i > 0 && fds[i].revents & POLLIN){
				if(DataHandle(fds[i].fd) <= 0){
					if( getpeername(fds[i].fd, (Addr *)&addr, &addrlen) < 0)
						perror("getpeername");
					printf("[%s:%d][fd=%d] exited.\n", 
							inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), fds[i].fd);
					close(fds[i].fd);
					for(j=i; j

socket.c

#include "net.h"

void Argment(int argc, char *argv[]){
	if(argc < 3){
		fprintf(stderr, "%s\n", argv[0]);
		exit(0);
	}
}
int CreateSocket(char *argv[]){
	/*创建套接字*/
	int fd = socket(AF_INET, SOCK_STREAM, 0);
	if(fd < 0)
		ErrExit("socket");
	/*允许地址快速重用*/
	int flag = 1;
	if( setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag) ) )
		perror("setsockopt");
	/*设置通信结构体*/
	Addr_in addr;
	bzero(&addr, sizeof(addr) );
	addr.sin_family = AF_INET;
	addr.sin_port = htons( atoi(argv[2]) );
	/*绑定通信结构体*/
	if( bind(fd, (Addr *)&addr, sizeof(Addr_in) ) )
		ErrExit("bind");
	/*设置套接字为监听模式*/
	if( listen(fd, BACKLOG) )
		ErrExit("listen");
	return fd;
}
int DataHandle(int fd){
	char buf[BUFSIZ] = {};
	Addr_in peeraddr;
	socklen_t peerlen = sizeof(Addr_in);
	if( getpeername(fd, (Addr *)&peeraddr, &peerlen) )
		perror("getpeername");
	int ret = recv(fd, buf, BUFSIZ, 0);
	if(ret < 0)
		perror("recv");
	if(ret > 0){
		printf("[%s:%d]data: %s\n", 
				inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port), buf);
	}
	return ret;
}

你可能感兴趣的:(我的小白学习笔记,LV9,网络编程及实战(下)),tcp/ip,网络,linux,c语言,服务器)