epoll编程实例客户端_socket采用epoll编程demo

epoll的结构体

typedef union epoll_data {

void *ptr;

int fd;

uint32_t u32;

uint64_t u64;

} epoll_data_t;

struct epoll_event {

uint32_t events; /* Epoll events */

epoll_data_t data; /* User data variable */

};

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define SERV_PORT 8802

int main()

{

int i,flag;

int sockfd,clntfd,newfd;

int epfd,nfds;

ssize_t n;

char buffer[1024];

int s = sizeof(struct sockaddr);

struct sockaddr_in serv_addr;

struct sockaddr_in clnt_addr;

//定义epoll数据结构

struct epoll_event ev,events[20];

epfd = epoll_create(256);

//创建socket,并初始化事件ev

sockfd = socket(AF_INET, SOCK_STREAM, 0);

if (sockfd < 0) {

perror("socket error!\n");

return -1;

}

ev.data.fd = sockfd;

ev.events = EPOLLIN|EPOLLET;

//注册epoll事件

flag = epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);

if (flag < 0) {

perror("epoll_ctl error!\n");

return -1;

}

bzero(&serv_addr, sizeof(serv_addr));

serv_addr.sin_family = AF_INET;

serv_addr.sin_port = htons(SERV_PORT);

serv_addr.sin_addr.s_addr = htonl( INADDR_ANY );

flag = bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(struct sockaddr));

if (flag < 0) {

perror("bind error!\n");

return -1;

}

printf("bind\n");

flag = listen(sockfd, 20);

if (flag < 0) {

perror("listen error!\n");

return -1;

}

printf("listen\n");

//开始循环

while (1) {

//等待事件发生,返回请求数目

nfds = epoll_wait(epfd, events, 20, 500);

//一次处理请求

for (i = 0; i < nfds; ++i) {

if (events[i].data.fd == sockfd){

clntfd = accept(sockfd, (struct sockaddr*)&clnt_addr,(unsigned int*)&s);

if (clntfd < 0) {

perror("accept error");

continue;

}

printf("accept\n");

char *str = inet_ntoa(clnt_addr.sin_addr);

printf("accepnt the client ip : %s\n",str);

//设置文件标识符,设置操作属性:写操作

ev.data.fd = clntfd;

ev.events = EPOLLOUT | EPOLLET;

//向创建的的epoll进行注册写操作

epoll_ctl(epfd, EPOLL_CTL_ADD, clntfd, &ev);

} else if (events[i].events & EPOLLOUT) {

printf("EPOLLOUT\n");

if ((newfd = events[i].data.fd) < 0)

continue;

bzero(buffer,sizeof(buffer));

strcpy(buffer,"welcome to myserver!\n");

flag = send(newfd, buffer, 1024, 0);

if (flag < 0) {

perror("send error");

continue;

}

//修改操作为读操作

ev.data.fd = clntfd;

ev.events = EPOLLIN | EPOLLET;

epoll_ctl(epfd, EPOLL_CTL_MOD, newfd, &ev);

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

printf("EPOLLIN\n");

bzero(buffer,sizeof(buffer));

if ((newfd = events[i].data.fd) < 0)

continue;

if ((n = read(newfd, buffer, 1024)) < 0) {

if (errno == ECONNRESET){

close(newfd);

events[i].data.fd = -1;

printf("errno ECONRESET!\n");

} else {

perror("readbuffer error!\n");

}

} else if (n == 0) {//表示客户端已经关闭

close(newfd);

events[i].data.fd = -1;

printf("n为0\n");

}

if (buffer[0] != '0')

printf("have read: %s\n", buffer);

}

}

}

close(sockfd);

return 0;

}

引自:https://www.bbsmax.com/A/l1dymR3Gde/

优化

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define SERV_PORT 8802

#define MAX_EVENTS 20

int main()

{

int listen_fd = socket(AF_INET, SOCK_STREAM, 0); //若成功则返回非负描述符,若失败则返回-1,第一个参数指明协议族(IPv4或IPv6等)

if (listen_fd < 0) { //第二个参数指明套接字类型,字节流套接字(SOCK_STREAM)和数据报套接字(SOCK_DGRAM)

perror("socket error!\n");

return -1;

}

int epfd = epoll_create(256); //参数会被忽略,但是要大于0,

//若成功返回一个大于 0 的值,表示 epoll 实例;若返回 -1 表示出错

//针对监听的sockfd,创建epollevent

struct epoll_event event;

event.data.fd = listen_fd;

event.events = EPOLLIN | EPOLLET;

//注册epoll事件

int flag = epoll_ctl(epfd, EPOLL_CTL_ADD, listen_fd, &event); //int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

if (flag < 0) { //成功返回0,出错返回-1

perror("epoll_ctl error!\n");

return -1;

}

if (bindAndListenFd(listen_fd) < 0)

return -1;

//定义epoll数据结构

struct epoll_event events[MAX_EVENTS]; //可以使用vector,参见muduo源码中的使用

while (1) {

//等待事件发生,返回请求数目

int nfds = epoll_wait(epfd, events, MAX_EVENTS, 500); //maxevents: 返回的events的最大个数,如果最大个数大于实际触发的个数,则下次epoll_wait的时候仍然可以返回

//int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

//成功返回的是一个大于 0 的数,表示事件的个数;返回 0 表示的是超时时间到;若出错返回 -1.

for (int i = 0; i < nfds; ++i) {

if (events[i].data.fd == listen_fd) {

struct sockaddr_in client_addr;

int client_fd = accept(listen_fd, (struct sockaddr*)&client_addr, sizeof(client_addr)); //若成功则为非负描述符,若出错则返回-1

if (client_fd < 0) {

perror("accept error");

continue;

}

char *str = inet_ntoa(client_addr.sin_addr);

printf("accept the client ip : %s\n",str);

onRecvNewConnect(epfd, client_fd);

} else if (events[i].events & EPOLLOUT) {

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

if (sockfd < 0)

continue;

onWriteFd(epfd, sockfd);

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

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

if (sockfd < 0)

continue;

if (onReadFd(epfd, sockfd) < 0) {

events[i].data.fd = -1;

}

}

}

}

close(sockfd);

return 0;

}

int bindAndListenFd(int sockfd) {

::fcntl(sockfd, F_SETFL, O_NONBLOCK); //设置非阻塞模式

struct sockaddr_in serv_addr;

bzero(&serv_addr, sizeof(serv_addr)); //void bzero(void *dest, size_t nbytes);

serv_addr.sin_family = AF_INET; //类似void *memset(void *dest, int c, size_t len);

serv_addr.sin_port = htons(SERV_PORT); //本地端口号转化为网络端口号 host to network short

serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY代表本机所有的IP地址 host to network long

int flag = bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); //成功返回0,出错返回-1

if (flag < 0) {

perror("bind error!\n");

return -1;

}

flag = listen(sockfd, 20); //成功返回0,出错返回-1

if (flag < 0) {

perror("listen error!\n");

return -1;

}

return 0;

}

void onRecvNewConnect(int epfd, int clientfd) {

::fcntl(sockfd, F_SETFL, O_NONBLOCK); //设置非阻塞模式

//设置文件标识符,设置操作属性:写操作

struct epoll_event ev_client;

ev_client.data.fd = clintfd;

ev_client.events = EPOLLOUT | EPOLLET;

//向创建的的epoll进行注册写操作

epoll_ctl(epfd, EPOLL_CTL_ADD, clientfd, &ev_client);

}

void onWriteFd(int epfd, int sockfd) {

char buffer[1024];

bzero(buffer, sizeof(buffer));

strcpy(buffer, "welcome to myserver!\n");

int flag = send(sockfd, buffer, 1024, 0);

if (flag < 0) {

perror("send error");

return;

}

//修改操作为读操作

struct epoll_event ev_client;

ev_client.data.fd = sockfd;

ev_client.events = EPOLLIN | EPOLLET;

epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev_client);

}

int onReadFd(int epfd, int sockfd) {

char buffer[1024];

bzero(buffer, sizeof(buffer));

int n = read(sockfd, buffer, 1024);

if (n < 0) {

if (errno == ECONNRESET) {

close(sockfd);

printf("errno ECONRESET!\n");

return -1;

} else {

perror("readbuffer error!\n");

}

} else if (n == 0) { //表示客户端已经关闭

close(sockfd);

printf("n为0\n");

return -1;

}

if (buffer[0] != '0')

printf("have read: %s\n", buffer);

return 0;

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值