linux 高级i o函数,7.10 第九章I/O复用高级函数 select poll epoll(lt et)

//所有内容均来自linux高性能服务器编程这本书.

利用epoll中的EPOLLONESHOT实现一段时间内只能有一个线程在处理一个SOKCET 防止该线程刚读取完数据准备处理 又来了一个数据 启动另外一个线程来处理 ONESHOT只会触发一次 所以当该工作进程处理完当前的事件之后,应该重置EPOLL_CTL_MOD 该FD状态 以便于下一次能够再次触发

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

// linux下使用结构体一定要在前面加入struct这个字 不然是没有效果的

#define MAX_EVENT_NUMBER 1024

#define BUFFER_SIZE 1024

// 由于之前没有什么敲linux下代码的经验

// 这次debug调式了很久的时间 需要注意的点就是如果是应用一个结构体 那么就需要在前面加入struct关键字 对于指针的传递一定要写&地址符号 (在实际编程中很少这样写 导致频繁出错) !!

typedef struct // 定义一个结构体

{

int epollfd;

int socket;

}fds;

int setnoblock(int fd)

{

int old_option = fcntl(fd,F_GETFL);

int new_option = old_option | O_NONBLOCK;

fcntl(fd,F_SETFL,new_option);

return old_option;

}

void addfd(int epollfd,int fd,bool oneshot)

{

struct epoll_event event;

event.data.fd = fd;

event.events = EPOLLIN | EPOLLET;

if(oneshot)

{

event.events |= EPOLLONESHOT;

}

epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,&event);

setnoblock(fd);

}

void reset_oneshot(int epollfd,int fd)

{

struct epoll_event event;

event.data.fd = fd;

event.events = EPOLLIN | EPOLLET | EPOLLONESHOT;

epoll_ctl(epollfd,EPOLL_CTL_MOD,fd,&event);

}

void* work(void* arg) // 主线程已经帮我连接了 为只是负责处理这个事件

{

int sockfd = (( fds* )arg)->socket;

int epollfd = (( fds* )arg)->epollfd;

printf("start new thread to receive msg on %d\n",socket);

char buf[BUFFER_SIZE];

memset(buf,0, BUFFER_SIZE);

while(1)

{

int ret = recv(sockfd,buf,BUFFER_SIZE - 1,0);

if(ret == 0)

{

close(socket);

printf("foreiner close the connect\n");

break;

}

else if(ret < 0)

{

if(errno == EAGAIN)

{

reset_oneshot(epollfd,socket);

printf("all revc and reset socket");

break;

}

}

else

{

printf("the msg is %s\n",buf);

sleep(5); // 模拟处理过程

}

printf("end thread receiving data on fd: %d\n",socket);

}

}

int main()

{

const char* ip = "";

int port = 80;

struct sockaddr_in address;

bzero(&address,sizeof address);

address.sin_family = AF_INET;

address.sin_port = htons(port);

inet_pton(AF_INET,ip,&address.sin_addr);

int listenfd = socket(PF_INET,SOCK_STREAM,0);

assert(listenfd >= 0);

int ret = bind(listenfd,(struct sockaddr *)&address,sizeof address);

assert(ret != -1);

ret = listen(listenfd,5);

assert(ret != -1);

struct epoll_event events[MAX_EVENT_NUMBER];

int epollfd = epoll_create(5);

addfd(epollfd,listenfd,false);

while(1)

{

int ret = epoll_wait(epollfd,events,MAX_EVENT_NUMBER,-1);

if(ret < 0)

{

printf("epoll failed");break;

}

for(int i = 0; i < ret ; i++)

{

int sockfd = events[i].data.fd;

if(sockfd == listenfd)

{

struct sockaddr_in client;

socklen_t len = sizeof(client);

int t = accept(sockfd,(struct sockaddr*)&client,&len);

addfd(epollfd,t,true);

}

else if(events[i].events & EPOLLIN)

{

pthread_t thread;

fds fds_for_new_work;

fds_for_new_work.epollfd = epollfd;

fds_for_new_work.socket = events[i].data.fd;

pthread_create(&thread,NULL,work,(void *)&fds_for_new_work); // 传递给工作线程的函数

}

else

{

printf("someting else happen\n");

}

}

}

close(listenfd);

return 0;

}

利用I/O复用 可以实现的高级功能有:

1.非阻塞的connect

同时发出多个链接 。用select监听有无读写数据

2.聊天室程序

多个用户同时在线进行聊天 poll I/O复用实现多用户在线聊天

客户端程序:

3.同时处理TCP和UDP服务

本文地址:https://blog.csdn.net/qq_41468712/article/details/107254109

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值