网络编程学习之路3-epoll
程序员文章站
2022-06-05 22:10:11
...
书接前文,前文书讲到使用多线程来处理tcp 连接,这次是使用单线程+epoll来处理tcp连接。
使用多线程来管理tcp连接,会增加多线程创建所代码的开销。系统所能接受的tcp连接数 = 系统内存/线程栈大小。我用的ubuntu默认栈大小是8M。1G的空间也只能创建128个tcp连接。当然可以通过增加内存或者调整栈空间大小来让单机接收更多连接。但始终不是一种高效的办法。
epoll api
//创建epoll实例
extern int epoll_create (int __size) ;
//用来增加或移除被epoll所监听的文件描述符
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
//等待epoll实例中注册的事件触发,timeout =-1表示无限等待
int epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout);
效果
同样是用telnet来测试,server端打印如下
[email protected]:~/share/mycode/c++/tcp-server-epoll$ ./bin/Debug/tcp-server-epoll
socket fd is 3
local ip =0.0.0.0
enter epoll_wait
epoll -wait end ,active_fd_num =1
accept connect success, client port=13475ip =127.0.0.1
newsockfd=5
enter epoll_wait
epoll -wait end ,active_fd_num =1
accept connect success, client port=14499ip =127.0.0.1
newsockfd=6
enter epoll_wait
epoll -wait end ,active_fd_num =1
accept connect success, client port=15011ip =127.0.0.1
newsockfd=7
enter epoll_wait
epoll -wait end ,active_fd_num =1
------------------------sockfd 5 start----------------
thread: 15156 sockfd:5 recv data:fdjaidf
------------------------sockfd 5 end----------------
enter epoll_wait
epoll -wait end ,active_fd_num =1
------------------------sockfd 5 start----------------
thread: 15156 sockfd:5 recv data:
------------------------sockfd 5 end----------------
enter epoll_wait
epoll -wait end ,active_fd_num =1
------------------------sockfd 6 start----------------
thread: 15156 sockfd:6 recv data:faifda
------------------------sockfd 6 end----------------
enter epoll_wait
epoll -wait end ,active_fd_num =1
------------------------sockfd 7 start----------------
thread: 15156 sockfd:7 recv data:fjiadfa
------------------------sockfd 7 end----------------
enter epoll_wait
epoll -wait end ,active_fd_num =1
------------------------sockfd 7 start----------------
thread: 15156 sockfd:7 recv data:
------------------------sockfd 7 end----------------
enter epoll_wait
代码
#include <iostream>
#include <arpa/inet.h>
#include <err.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <thread>
#include <sys/epoll.h>
#define PORT 12351
#define MAXSIZE 10240
#define MAX_EVENT 100
using namespace std;
void read_data(int sockfd){
printf("------------------------sockfd %d start----------------\n", sockfd);
long tid = getpid();
char *buffer = (char*)malloc( 1000 * sizeof(char));
int n = read(sockfd, (void*)buffer, sizeof(buffer)/sizeof(char));
if(n ==-1){
perror("read error");
strerror(errno);
std::cout<<"socket fd =" << sockfd<<std::endl;
free(buffer);
exit(errno);
}
std::cout<< "thread: "<<tid << " sockfd:"<<sockfd<<" recv data:" <<string(buffer,n)<<std::endl;
free(buffer);
printf("------------------------sockfd %d end----------------\n", sockfd);
}
int main(int args, char *argv[])
{
// cout << "Hello world!" << endl;
int sockfd, newsockfd;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
int sin_size, portnum;
char buf[MAX_EVENT][MAXSIZE] = {0};
int epfd ;
int active_fd_num;
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
fprintf(stderr, "create socket failed!");
strerror(errno);
close(sockfd);
exit(1);
}
std::cout<<"socket fd is " << sockfd <<std::endl;
bzero(&server_addr, sizeof(struct sockaddr_in));
server_addr.sin_port = htons(PORT);
server_addr.sin_family = AF_INET;
// server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_addr.s_addr = inet_addr("0.0.0.0");
if( bind(sockfd, (struct sockaddr*)(&server_addr), sizeof(struct sockaddr))){
fprintf(stderr, "bind failed");
strerror(errno);
close(sockfd);
exit(2);
}
struct sockaddr_in local_addr;
int len;
if (getsockname(sockfd, (struct sockaddr *)&local_addr, (socklen_t* )&len) == 0) {
struct sockaddr_in* sin = (struct sockaddr_in*)(&local_addr);
// *port = sin->sin_port;
char addr_buffer[INET_ADDRSTRLEN];
void * tmp = &(sin->sin_addr);
if (inet_ntop(AF_INET, tmp, addr_buffer, INET_ADDRSTRLEN) == NULL){
cerr << "inet_ntop err";
return false;
}
printf("local ip =%s\n", addr_buffer);
}
if(listen(sockfd, 10) < 0){
fprintf(stderr,"listen failed");
strerror(errno);
close(sockfd);
exit(3);
}
sin_size = sizeof(struct sockaddr_in);
//create epoll fd
if((epfd = epoll_create(100)) == -1){
fprintf(stderr, "create epoll fd failed!");
strerror(errno);
close(epfd);
exit(1);
}
struct epoll_event ev, active_events[100];
ev.data.fd = sockfd;
ev.events = EPOLLIN;
if(epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev) == -1){
fprintf(stderr, "add sock fd failed!");
strerror(errno);
close(epfd);
exit(1);
}
while(1){
std::cout<<"enter epoll_wait" <<std::endl;
active_fd_num = epoll_wait(epfd, active_events, MAX_EVENT, -1);//-1
if(active_fd_num <= 0)
continue;
std::cout<<"epoll -wait end ,active_fd_num =" << active_fd_num<<std::endl;
for(int i =0; i<active_fd_num ; i++){
if(active_events[i].data.fd == sockfd){
if( (newsockfd = accept(sockfd, (struct sockaddr *) (&client_addr),(socklen_t*) &sin_size))< 0){
fprintf(stderr, "listen failed");
strerror(errno);
exit(3);
}
std::cout<<"accept connect success, client port=" << client_addr.sin_port<<
"ip =" <<inet_ntoa(client_addr.sin_addr)<<std::endl;
std::cout<< "newsockfd=" << newsockfd<<std::endl;
active_events[i].events = EPOLLIN;
active_events[i].data.fd = newsockfd;
if(epoll_ctl(epfd, EPOLL_CTL_ADD, newsockfd, &active_events[i]) == -1){
fprintf(stderr, "add sock fd failed!");
strerror(errno);
close(epfd);
exit(1);
}
}else {
read_data(active_events[i].data.fd);
}
}
}
for(int i =0; i<MAX_EVENT ;i++){
if( active_events[i].data.fd != 0)
close(active_events[i].data.fd);
}
return 0;
}
下一篇: 利用Python获取赶集网招聘信息前篇
推荐阅读
-
python网络编程学习笔记(七):HTML和XHTML解析(HTMLParser、BeautifulSoup)
-
python网络编程学习笔记(九):数据库客户端 DB-API
-
22岁学习网页编程,学了是PHP、ASP,大侠们支招小弟我该怎么走编程之路
-
java网络编程学习java聊天程序代码分享
-
muduo 网络库学习之路(一)
-
python网络编程学习笔记(九):数据库客户端 DB-API
-
python网络编程学习笔记(10):webpy框架
-
python网络编程学习笔记(六):Web客户端访问
-
python网络编程学习笔记(八):XML生成与解析(DOM、ElementTree)
-
python网络编程学习笔记(五):socket的一些补充