Linux事件驱动网络编程,七、linux网络编程

异步I、O之epoll

有时为了处理大量的文件句柄,需要一种机制,在单线程中也可以处理多个socket请求,轮询的机制可以实现但是对系统的负载较高,epoll是linux系统用来处理类似socket这样的文件句柄的读写等操作的一种IO复用机制。服务端维护一个socket列表,使用epoll调用来取出准备好读或写的socket,随后可以对socket句柄进行操作

用到的系统调用epoll_create/epoll_ctl/epoll_wait

用到的数据结构epoll_event/epoll_data_t

查阅manual了解函数用法

一个简单的例子

common.h

//include the header file socket,io,epoll,list,string,unistd,stdlib

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

//namespace

using namespace std;

//client list, C++ stl list

list client_list;

//macro statement server_ip,server_port,epollsize,buf_size,Welcome string,server_string

#define SERVER_IP "127.0.0.1"

#define SERVER_PORT 8888

#define EPOLL_SIZE 500

#define BUF_SIZE 2048

#define WELCOME_STRING "Welcome to join the chat room, your chat ID is: Client# %d"

#define SERVER_STRING "Client id #%d say >> %s"

#define CAUTION "only one client in the chat room"

//set fd in nonblocking io mode, using fnctl

void setNonBlocking(int fd){

int res = fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | O_NONBLOCK);

if(res != 0){

perror("set fd nonblock failed");

return;

}

}

//add fd to the epoll,with epoll_ctl

void addFdToEpoll(int epollfd, int sockfd, bool enable_et){

struct epoll_event event;

event.events = EPOLLIN;

if(enable_et){

event.events = EPOLLIN | EPOLLET;

}

event.data.fd = sockfd;

if(epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &event) != 0){

perror("add fd to epoll failed");

};

setNonBlocking(sockfd);

}

//send broadcast message to the client in clients list, except for which we received the data

void sendBroadcastMessage(int sockfd){

char buf[BUF_SIZE], message[BUF_SIZE];

//initialize the space

bzero(buf, BUF_SIZE);

bzero(message, BUF_SIZE);

int rlen = recv(sockfd, buf, BUF_SIZE, 0);

printf("read data from Client #%d: %s\n", sockfd, buf);

if(rlen == 0){

close(sockfd);

client_list.remove(sockfd);

printf("client #%ld closed, Now, there are %d clients in the chatroom\n",sockfd, client_list.size());

}else{

if(client_list.size() == 1){

int slen = send(sockfd, CAUTION, strlen(CAUTION), 0);

return;

}

sprintf(message, SERVER_STRING, sockfd, buf);

printf("will send:%s\n", message);

list::iterator iter;

for( iter = client_list.begin(); iter != client_list.end(); iter++ ){

puts("sending data...");

if(*iter != sockfd){

send(*iter, message, BUF_SIZE, 0);

}

}

}

}

server.c

#include "common.h"

int main(){

//socket address statement

struct sockaddr_in server_addr;

//initialize the address

server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);

server_addr.sin_port = htons(SERVER_PORT);

server_addr.sin_family = AF_INET;

//create server socket

int listener = socket(AF_INET, SOCK_STREAM, 0);

//bind the server address

if(bind(listener, (struct sockaddr*)&server_addr, sizeof(server_addr)) != 0){

perror("bind failed");

return 1;

}

//listen on the address

if(listen(listener, 5) != 0){

perror("listen failed");

return 2;

}

//create epoll

int epollfd = epoll_create(EPOLL_SIZE);

if(epollfd < 0){

perror("create epollfd failed");

return 3;

}

//add server fd to epoll

addFdToEpoll(epollfd, listener, true);

//epoll_event array

static struct epoll_event events[EPOLL_SIZE];

//main loop

int clientfd;

while(1){

//epoll_wait

puts("waiting clients...");

int event_count = epoll_wait(epollfd,events, EPOLL_SIZE, -1);

printf("epoll event count is %d\n", event_count);

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

clientfd = events[i].data.fd;

//if fd is serverfd, accept a connection, print information, add new sockfd to epoll

if(clientfd == listener){

struct sockaddr_in client_addr;

socklen_t addrlen = sizeof(struct sockaddr_in);

int newfd = accept(listener, (struct sockaddr*)&client_addr, &addrlen);

if(newfd < 0){

perror("accept new connections failed");

exit(EXIT_FAILURE);

}

printf(

"new connection from %s:%d, client id #%d\n",

inet_ntoa(client_addr.sin_addr),

ntohs(client_addr.sin_port),

newfd

);

addFdToEpoll(epollfd, newfd, true);

client_list.push_back(newfd);

printf("welcome message\n");

char message[BUF_SIZE];

bzero(message, BUF_SIZE);

sprintf(message, WELCOME_STRING, newfd);

send(newfd, message, strlen(message), 0);

}//if not, sendbroadcast message

else{

sendBroadcastMessage(clientfd);

}

}

}

}

client.c

#include"common.h"

int main(){

//server address statement

struct sockaddr_in server_addr;

//initilize server address

server_addr.sin_family = AF_INET;

server_addr.sin_port = htons(SERVER_PORT);

server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);

//create sock

int sock = socket(AF_INET, SOCK_STREAM, 0);

if(sock < 0){

perror("create socket failed");

return 1;

}

if(connect(sock, (struct sockaddr*)&server_addr, sizeof(struct sockaddr_in)) != 0){

perror("connect server failed");

return 0;

}

int pipefd[2];

if(pipe(pipefd) != 0){

perror("create pipe failed");

return 2;

}

int epollfd = epoll_create(EPOLL_SIZE);

if(epollfd< 0){

perror("create epollfd failed");

return 3;

}

addFdToEpoll(epollfd, sock, true);

addFdToEpoll(epollfd, pipefd[0], true);

pid_t pid = fork();

if(pid < 0){

perror("create child process failed");

return 4;

}

int client_running = 1;

char message[BUF_SIZE];

char buf[BUF_SIZE];

struct epoll_event events[2];

if(pid == 0){

close(pipefd[0]);

printf("please input your message, and type exit to terminate\n");

while(client_running){

//printf("input>");

bzero(message, BUF_SIZE);

//bzero(buf, BUF_SIZE);

fgets(message, BUF_SIZE, stdin);

if(strncmp(message, "exit", strlen("exit")) == 0){

client_running = 0;

close(sock);

close(pipefd[1]);

return 0;

}else{

write(pipefd[1], message, strlen(message));

}

}

}else{

close(pipefd[1]);

while(client_running){

int event_count = epoll_wait(epollfd, events, 2, -1);

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

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

bzero(buf, BUF_SIZE);

if(read(pipefd[0], buf, BUF_SIZE) == 0){

client_running = 0;

}else{

printf("\nyour input:%s\n", buf);

send(sock, buf, strlen(buf) - 1, 0);

}

}else{

recv(sock, buf, BUF_SIZE, 0);

printf("\nServer message:%s\n", buf);

}

}

}

}

close(sock);

if(pid){

close(pipefd[0]);

}else{

close(pipefd[1]);

}

return 0;

}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值