当前位置: 首页 > news >正文

本地搭建网站百度竞价包年推广是怎么回事

本地搭建网站,百度竞价包年推广是怎么回事,网上做任务网站,杭州模板网站制作方案select初识 select是系统提供的一个多路转接接口。 select系统调用可以让我们的程序同时监视多个文件描述符的上的事件是否就绪。 select的核心工作就是等,当监视的多个文件描述符中有一个或多个事件就绪时,select才会成功返回并将对应文件描述符的就绪…

select初识
select是系统提供的一个多路转接接口。

select系统调用可以让我们的程序同时监视多个文件描述符的上的事件是否就绪。
select的核心工作就是等,当监视的多个文件描述符中有一个或多个事件就绪时,select才会成功返回并将对应文件描述符的就绪事件告知调用者。
 

select基本工作流程
如果我们要实现一个简单的select服务器,该服务器要做的就是读取客户端发来的数据并进行打印,那么这个select服务器的工作流程应该是这样的:

先初始化服务器,完成套接字的创建、绑定和监听。
定义一个fd_array数组用于保存监听套接字和已经与客户端建立连接的套接字,刚开始时就将监听套接字添加到fd_array数组当中。
然后服务器开始循环调用select函数,检测读事件是否就绪,如果就绪则执行对应的操作。
每次调用select函数之前,都需要定义一个读文件描述符集readfds,并将fd_array当中的文件描述符依次设置进readfds当中,表示让select帮我们监视这些文件描述符的读事件是否就绪。
当select检测到数据就绪时会将读事件就绪的文件描述符设置进readfds当中,此时我们就能够得知哪些文件描述符的读事件就绪了,并对这些文件描述符进行对应的操作。
如果读事件就绪的是监听套接字,则调用accept函数从底层全连接队列获取已经建立好的连接,并将该连接对应的套接字添加到fd_array数组当中。
如果读事件就绪的是与客户端建立连接的套接字,则调用read函数读取客户端发来的数据并进行打印输出。
当然,服务器与客户端建立连接的套接字读事件就绪,也可能是因为客户端将连接关闭了,此时服务器应该调用close关闭该套接字,并将该套接字从fd_array数组当中清除,因为下一次不需要再监视该文件描述符的读事件了。
 

log.hpp

#pragma once#include <iostream>
#include <cstdio>
#include <cstdarg>
#include <ctime>
#include <string>// 日志是有日志级别的
#define DEBUG   0
#define NORMAL  1
#define WARNING 2
#define ERROR   3
#define FATAL   4const char *gLevelMap[] = {"DEBUG","NORMAL","WARNING","ERROR","FATAL"
};#define LOGFILE "./selectServer.log"// 完整的日志功能,至少: 日志等级 时间 支持用户自定义(日志内容, 文件行,文件名)
void logMessage(int level, const char *format, ...)
{// va_list ap;// va_start(ap, format);// while()// int x = va_arg(ap, int);// va_end(ap); //ap=nullptrchar stdBuffer[1024]; //标准部分time_t timestamp = time(nullptr);// struct tm *localtime = localtime(&timestamp);snprintf(stdBuffer, sizeof stdBuffer, "[%s] [%ld] ", gLevelMap[level], timestamp);char logBuffer[1024]; //自定义部分va_list args;va_start(args, format);// vprintf(format, args);vsnprintf(logBuffer, sizeof logBuffer, format, args);va_end(args);// FILE *fp = fopen(LOGFILE, "a");printf("%s%s\n", stdBuffer, logBuffer);// fprintf(fp, "%s%s\n", stdBuffer, logBuffer);// fclose(fp);
}

selectserver.hpp

#include <iostream>
#include <cstring>
#include <sys/select.h>
#include "log.hpp"
#include "sock.hpp"
#include <string>
#include <vector>
#include <sys/types.h>
#include <sys/time.h>
#include <algorithm>
#define NUM 1024
#define FD_NONE -1
using namespace std;
class SelectServer
{
public://端口类型设置为16位是因为TCP报文中端口号为16位SelectServer(const uint16_t &port = 8080):_port(port){_listensock = Sock::Socket();Sock::Bind(_listensock,_port);Sock::Listen(_listensock);logMessage(DEBUG,"%s","create base socket success");for(int i = 0;i < NUM;i++) _fd_array[i] = FD_NONE;_fd_array[0] = _listensock;//规定第一个为监听套接字std::cout<<"初始化完成...."<<std::endl;} void start(){while(1){struct timeval timeout = {0,0};fd_set rfds;FD_ZERO(&rfds);int maxfd = _listensock;for(int i = 0;i < NUM;i++){if(_fd_array[i] == FD_NONE) continue;FD_SET(_fd_array[i],&rfds);maxfd = max(maxfd,_fd_array[i]);}int n = select(maxfd + 1,&rfds,nullptr, nullptr,&timeout);DebugPrint();switch (n){case 0:sleep(1);logMessage(DEBUG,"%s","time out...");break;case -1:logMessage(DEBUG,"%s","select error");break;default://成功logMessage(DEBUG,"%s","get a new link event........");//成功了的话,如果不去读取的话会一直提醒读取,也就是说链接好的//链接会被放在就绪队列中,也就是看到链接在排队,操作系统会一直提醒有连接成功//当你要取的时候会取队列的头部连接去执行//因为我们的select是检查_listensock有没有获取的连接已经到达Tcp层//如果到达的话,就说明可以读走这个链接了,所以我们检查的是IO//也就是读到连接的操作,而不是建立连接的操作HandlerEvent(rfds);sleep(1);break;}}}private:uint16_t _port;int _listensock;int _fd_array[NUM];void HandlerEvent(const fd_set &rfds){for(int i = 0;i < NUM;i++){//1.去掉不合法的fd,也就是去掉没有建立连接的fd,也就是去掉数组里为FD_NONEif(_fd_array[i] == FD_NONE) continue;//2.合法的就一定就绪了?,不一定,所以需要FD_ISSET判断是否已经就绪if(FD_ISSET(_fd_array[i],&rfds)){//1.如果是监听套接字就绪了,那就是accept//2.如果不是的话,那就处理该链接,进行读取函数if(_fd_array[i] == _listensock) Accepter();else Recver(i);}}}void Accepter(){string clientip;uint16_t clientport;int sock = Sock::Accept(_listensock,&clientip,&clientport);if(sock < 0){logMessage(WARNING,"%s %s:%d","accept error",strerror(errno),errno);return;}logMessage(DEBUG,"get a new link success");int pos = 0;for(;pos < NUM;pos++){if(_fd_array[pos] == FD_NONE) break;}if(pos == NUM){logMessage(WARNING, "%s:%d", "select server already full,close: %d", sock);close(sock);}else{_fd_array[pos] = sock;}}void Recver(int pos){logMessage(DEBUG,"message in,get IO event:%d",_fd_array[pos]);// 暂时先不做封装, 此时select已经帮我们进行了事件检测,fd上的数据一定是就绪的,即 本次 不会被阻塞// 这样读取有bug吗?有的,你怎么保证以读到了一个完整包文呢?char buffer[1024];int n = recv(_fd_array[pos],buffer,sizeof(buffer) - 1,0);//不会堵塞,if(n > 0){buffer[n] = 0;logMessage(DEBUG,"client[%d]# %s",_fd_array[pos],buffer);}else if(n == 0){logMessage(DEBUG, "client[%d] quit, me too...", _fd_array[pos]);//对端关闭那么我也关闭close(_fd_array[pos]);_fd_array[pos] = FD_NONE;}else{logMessage(WARNING, "%d sock recv error, %d : %s", _fd_array[pos], errno, strerror(errno));close(_fd_array[pos]);_fd_array[pos] = FD_NONE;}}void DebugPrint(){cout << "_fd_array[]: ";for(int i = 0; i < NUM; i++){if(_fd_array[i] == FD_NONE) continue;cout << _fd_array[i] << " ";}cout << endl;}
};

 sock.hpp

#pragma once#include <iostream>
#include <string>
#include <cstring>
#include <cerrno>
#include <cassert>
#include <unistd.h>
#include <memory>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <ctype.h>//全加静态成员让他变成一个方法
class Sock
{
private:// listen的第二个参数,意义:底层全连接队列的长度 = listen的第二个参数+1const static int gbacklog = 10;
public:Sock() {}static int Socket(){int listensock = socket(AF_INET, SOCK_STREAM, 0);if (listensock < 0){exit(2);}int opt = 1;setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));return listensock;}static void Bind(int sock, uint16_t port, std::string ip = "0.0.0.0"){struct sockaddr_in local;memset(&local, 0, sizeof local);local.sin_family = AF_INET;local.sin_port = htons(port);inet_pton(AF_INET, ip.c_str(), &local.sin_addr);if (bind(sock, (struct sockaddr *)&local, sizeof(local)) < 0){exit(3);}}static void Listen(int sock){if (listen(sock, gbacklog) < 0){exit(4);}}// 一般经验// const std::string &: 输入型参数// std::string *: 输出型参数// std::string &: 输入输出型参数static int Accept(int listensock, std::string *ip, uint16_t *port){struct sockaddr_in src;socklen_t len = sizeof(src);int servicesock = accept(listensock, (struct sockaddr *)&src, &len);if (servicesock < 0){return -1;}if(port) *port = ntohs(src.sin_port);if(ip) *ip = inet_ntoa(src.sin_addr);return servicesock;}static bool Connect(int sock, const std::string &server_ip, const uint16_t &server_port){struct sockaddr_in server;memset(&server, 0, sizeof(server));server.sin_family = AF_INET;server.sin_port = htons(server_port);server.sin_addr.s_addr = inet_addr(server_ip.c_str());if(connect(sock, (struct sockaddr*)&server, sizeof(server)) == 0) return true;else return false;}~Sock() {}
};

 main.cc

 

#include "selectserver.hpp"
using namespace std;
int main()
{SelectServer select;cout<<"runring......."<<endl;select.start();
}

I/O多路转接之poll

poll初识

poll也是系统提供的一个多路转接接口。

  • poll系统调用也可以让我们的程序同时监视多个文件描述符上的事件是否就绪,和select的定位是一样的,适用场景也是一样的。

poll的工作流程和select是基本类似的,这里我们也实现一个简单poll服务器,该服务器也只是读取客户端发来的数据并进行打印。

log.hpp

#pragma once#include <iostream>
#include <cstdio>
#include <cstdarg>
#include <ctime>
#include <string>// 日志是有日志级别的
#define DEBUG   0
#define NORMAL  1
#define WARNING 2
#define ERROR   3
#define FATAL   4const char *gLevelMap[] = {"DEBUG","NORMAL","WARNING","ERROR","FATAL"
};#define LOGFILE "./selectServer.log"// 完整的日志功能,至少: 日志等级 时间 支持用户自定义(日志内容, 文件行,文件名)
void logMessage(int level, const char *format, ...)
{// va_list ap;// va_start(ap, format);// while()// int x = va_arg(ap, int);// va_end(ap); //ap=nullptrchar stdBuffer[1024]; //标准部分time_t timestamp = time(nullptr);// struct tm *localtime = localtime(&timestamp);snprintf(stdBuffer, sizeof stdBuffer, "[%s] [%ld] ", gLevelMap[level], timestamp);char logBuffer[1024]; //自定义部分va_list args;va_start(args, format);// vprintf(format, args);vsnprintf(logBuffer, sizeof logBuffer, format, args);va_end(args);// FILE *fp = fopen(LOGFILE, "a");printf("%s%s\n", stdBuffer, logBuffer);// fprintf(fp, "%s%s\n", stdBuffer, logBuffer);// fclose(fp);
}

pollserver.hpp

#include <iostream>
#include <cstring>
#include <sys/select.h>
#include "log.hpp"
#include "sock.hpp"
#include <string>
#include <vector>
#include <sys/types.h>
#include <sys/time.h>
#include <algorithm>
#include <poll.h>
#define NUM 1024
#define FD_NONE -1
using namespace std;
class PollServer
{
public:static const int nfds = 100;
public:// struct pollfd {//     int   fd;         // 文件描述符//     short events;     // 需要关注的事件//     short revents;    // 实际发生的事件// };
//  fd:待轮询的文件描述符。
// events:关注的事件,可以是以下值的组合:
// POLLIN:可读事件(数据可读取)
// POLLOUT:可写事件(数据可写入)
// POLLERR:错误事件(发生错误)
// POLLHUP:挂起事件(连接断开)
// POLLNVAL:无效事件(文件描述符未打开)
// revents:实际发生的事件,在调用 poll 后由系统设置。
// poll 函数将在等待期间阻塞,并返回发生事件的数量,如果超时则返回 0,如果出错则返回 -1。// 您可以使用 poll 函数来同时监视多个文件描述符,并根据发生的事件采取相应的操作。//端口类型设置为16位是因为TCP报文中端口号为16位PollServer(const uint16_t &port = 8080):_port(port),_nfds(nfds){_listensock = Sock::Socket();Sock::Bind(_listensock,_port);Sock::Listen(_listensock);logMessage(DEBUG,"%s","create base socket success");_fds = new struct pollfd[_nfds];for(int i = 0;i < NUM;i++) {_fds[i].fd = FD_NONE;_fds[i].events = _fds[i].revents = 0;} _fds[0].fd= _listensock;//规定第一个为监听套接字,需要关注的套接字是什么,这是对象方面_fds[0].events = POLLIN;//需要套接字中关注的事件是读事件,这个才是关系的动作_timeout = 1000;std::cout<<"初始化完成...."<<std::endl;} void start(){while(1){int n = poll(_fds,_nfds,_timeout);DebugPrint();switch (n){case 0:sleep(1);logMessage(DEBUG,"%s","time out...");break;case -1:logMessage(DEBUG,"%s","select error");break;default://成功logMessage(DEBUG,"%s","get a new link event........");//成功了的话,如果不去读取的话会一直提醒读取,也就是说链接好的//链接会被放在就绪队列中,也就是看到链接在排队,操作系统会一直提醒有连接成功//当你要取的时候会取队列的头部连接去执行//因为我们的select是检查_listensock有没有获取的连接已经到达Tcp层//如果到达的话,就说明可以读走这个链接了,所以我们检查的是IO//也就是读到连接的操作,而不是建立连接的操作HandlerEvent();sleep(1);break;}}}~PollServer(){if(_listensock >= 0) close(_listensock);if(!_fds) delete [] _fds;}
private:uint16_t _port;int _listensock;int _timeout;struct pollfd* _fds;int _nfds;void HandlerEvent(){for(int i = 0;i < _nfds;i++){//1.去掉不合法的fd,也就是去掉没有建立连接的fd,也就是去掉数组里为FD_NONEif(_fds[i].fd == FD_NONE) continue;//2.合法的就一定就绪了?,不一定,所以需要FD_ISSET判断是否已经就绪if(_fds[i].revents & POLLIN)//判断读事件是否就绪,就是就是一个数字{//1.如果是监听套接字就绪了,那就是accept//2.如果不是的话,那就处理该链接,进行读取函数if(_fds[i].fd == _listensock) Accepter();else Recver(i);}}}void Accepter(){string clientip;uint16_t clientport;int sock = Sock::Accept(_listensock,&clientip,&clientport);if(sock < 0){logMessage(WARNING,"%s %s:%d","accept error",strerror(errno),errno);return;}logMessage(DEBUG,"get a new link success");int pos = 0;for(;pos < NUM;pos++){if(_fds[pos].fd == FD_NONE) break;}if(pos == NUM){logMessage(WARNING, "%s:%d", "select server already full,close: %d", sock);close(sock);}else{_fds[pos].fd = sock;_fds[pos].events = POLLIN;}}void Recver(int pos){logMessage(DEBUG,"message in,get IO event:%d",_fds[pos].fd);// 暂时先不做封装, 此时select已经帮我们进行了事件检测,fd上的数据一定是就绪的,即 本次 不会被阻塞// 这样读取有bug吗?有的,你怎么保证以读到了一个完整包文呢?char buffer[1024];int n = recv(_fds[pos].fd,buffer,sizeof(buffer) - 1,0);//不会堵塞,if(n > 0){buffer[n] = 0;logMessage(DEBUG,"client[%d]# %s",_fds[pos].fd,buffer);}else if(n == 0){logMessage(DEBUG, "client[%d] quit, me too...", _fds[pos].fd);//对端关闭那么我也关闭close(_fds[pos].fd);_fds[pos].fd = FD_NONE;_fds[pos].events = 0;}else{logMessage(WARNING, "%d sock recv error, %d : %s", _fds[pos].fd, errno, strerror(errno));close(_fds[pos].fd);_fds[pos].fd = FD_NONE;_fds[pos].fd = 0;}}void DebugPrint(){cout << "_fd_array[]: ";for(int i = 0; i < NUM; i++){if(_fds[i].fd  == FD_NONE) continue;cout << _fds[i].fd << " ";}cout << endl;}
};

sock.hpp

#pragma once#include <iostream>
#include <string>
#include <cstring>
#include <cerrno>
#include <cassert>
#include <unistd.h>
#include <memory>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <ctype.h>class Sock
{
private:// listen的第二个参数,意义:底层全连接队列的长度 = listen的第二个参数+1const static int gbacklog = 10;
public:Sock() {}static int Socket(){int listensock = socket(AF_INET, SOCK_STREAM, 0);if (listensock < 0){exit(2);}int opt = 1;setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));return listensock;}static void Bind(int sock, uint16_t port, std::string ip = "0.0.0.0"){struct sockaddr_in local;memset(&local, 0, sizeof local);local.sin_family = AF_INET;local.sin_port = htons(port);inet_pton(AF_INET, ip.c_str(), &local.sin_addr);if (bind(sock, (struct sockaddr *)&local, sizeof(local)) < 0){exit(3);}}static void Listen(int sock){if (listen(sock, gbacklog) < 0){exit(4);}}// 一般经验// const std::string &: 输入型参数// std::string *: 输出型参数// std::string &: 输入输出型参数static int Accept(int listensock, std::string *ip, uint16_t *port){struct sockaddr_in src;socklen_t len = sizeof(src);int servicesock = accept(listensock, (struct sockaddr *)&src, &len);if (servicesock < 0){return -1;}if(port) *port = ntohs(src.sin_port);if(ip) *ip = inet_ntoa(src.sin_addr);return servicesock;}static bool Connect(int sock, const std::string &server_ip, const uint16_t &server_port){struct sockaddr_in server;memset(&server, 0, sizeof(server));server.sin_family = AF_INET;server.sin_port = htons(server_port);server.sin_addr.s_addr = inet_addr(server_ip.c_str());if(connect(sock, (struct sockaddr*)&server, sizeof(server)) == 0) return true;else return false;}~Sock() {}
};

 main.cc

#include "pollserver.hpp"
using namespace std;
int main()
{PollServer pollserver;cout<<"runring......."<<endl;pollserver.start();
}

/O多路转接之epoll
epoll初识
epoll也是系统提供的一个多路转接接口。

epoll系统调用也可以让我们的程序同时监视多个文件描述符上的事件是否就绪,与select和poll的定位是一样的,适用场景也相同。
epoll在命名上比poll多了一个e,这个e可以理解成是extend,epoll就是为了同时处理大量文件描述符而改进的poll。
epoll在2.5.44内核中被引进,它几乎具备了select和poll的所有优点,被公认为Linux2.6下性能最好的多路I/O就绪通知方法。
epoll的相关系统调用
epoll有三个相关的系统调用,分别是epoll_create、epoll_ctl和epoll_wait。

epoll工作原理


 

 epoll.hpp

#pragma once
#include <iostream>
#include <sys/epoll.h>
#include <unistd.h>
using namespace std;
class Epoll
{
public:static const int gsize = 256;
public:static int CreateEpoll(){int epfd = epoll_create(gsize);if(epfd > 0) return epfd;exit(5);}static bool CtrlEpoll(int epfd,int oper,int sock,uint32_t events){struct epoll_event ev;ev.events = events;ev.data.fd = sock;int n = epoll_ctl(epfd,oper,sock,&ev);return n == 0;}static int WaitEpoll(int epfd,struct epoll_event* revs,int num,int timeout){// 细节1:如果底层就绪的sock非常多,revs承装不下,怎么办??不影响!一次拿不完,就下一次再拿// 细节2:关于epoll_wait的返回值问题:有几个fd上的事件就绪,就返回几,epoll返回的时候,会将所有//       就绪的event按照顺序放入到revs数组中!一共有返回值个!return epoll_wait(epfd,revs,num,timeout);}
};

 log.hpp

#pragma once#include <iostream>
#include <cstdio>
#include <cstdarg>
#include <ctime>
#include <string>// 日志是有日志级别的
#define DEBUG   0
#define NORMAL  1
#define WARNING 2
#define ERROR   3
#define FATAL   4const char *gLevelMap[] = {"DEBUG","NORMAL","WARNING","ERROR","FATAL"
};#define LOGFILE "./selectServer.log"// 完整的日志功能,至少: 日志等级 时间 支持用户自定义(日志内容, 文件行,文件名)
void logMessage(int level, const char *format, ...)
{// va_list ap;// va_start(ap, format);// while()// int x = va_arg(ap, int);// va_end(ap); //ap=nullptrchar stdBuffer[1024]; //标准部分time_t timestamp = time(nullptr);// struct tm *localtime = localtime(&timestamp);snprintf(stdBuffer, sizeof stdBuffer, "[%s] [%ld] ", gLevelMap[level], timestamp);char logBuffer[1024]; //自定义部分va_list args;va_start(args, format);// vprintf(format, args);vsnprintf(logBuffer, sizeof logBuffer, format, args);va_end(args);// FILE *fp = fopen(LOGFILE, "a");printf("%s%s\n", stdBuffer, logBuffer);// fprintf(fp, "%s%s\n", stdBuffer, logBuffer);// fclose(fp);
}

sock.hpp

#pragma once#include <iostream>
#include <string>
#include <cstring>
#include <cerrno>
#include <cassert>
#include <unistd.h>
#include <memory>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <ctype.h>//全加静态成员让他变成一个方法
class Sock
{
private:// listen的第二个参数,意义:底层全连接队列的长度 = listen的第二个参数+1const static int gbacklog = 10;
public:Sock() {}static int Socket(){int listensock = socket(AF_INET, SOCK_STREAM, 0);if (listensock < 0){exit(2);}int opt = 1;setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));return listensock;}static void Bind(int sock, uint16_t port, std::string ip = "0.0.0.0"){struct sockaddr_in local;memset(&local, 0, sizeof local);local.sin_family = AF_INET;local.sin_port = htons(port);inet_pton(AF_INET, ip.c_str(), &local.sin_addr);if (bind(sock, (struct sockaddr *)&local, sizeof(local)) < 0){exit(3);}}static void Listen(int sock){if (listen(sock, gbacklog) < 0){exit(4);}}// 一般经验// const std::string &: 输入型参数// std::string *: 输出型参数// std::string &: 输入输出型参数static int Accept(int listensock, std::string *ip, uint16_t *port){struct sockaddr_in src;socklen_t len = sizeof(src);int servicesock = accept(listensock, (struct sockaddr *)&src, &len);if (servicesock < 0){return -1;}if(port) *port = ntohs(src.sin_port);if(ip) *ip = inet_ntoa(src.sin_addr);return servicesock;}static bool Connect(int sock, const std::string &server_ip, const uint16_t &server_port){struct sockaddr_in server;memset(&server, 0, sizeof(server));server.sin_family = AF_INET;server.sin_port = htons(server_port);server.sin_addr.s_addr = inet_addr(server_ip.c_str());if(connect(sock, (struct sockaddr*)&server, sizeof(server)) == 0) return true;else return false;}~Sock() {}
};

epollserver.hpp

#include "sock.hpp"
#include "log.hpp"
#include <memory>
#include <sys/types.h>
#include <cstring>
#include <functional>
#include <string>
#include "epoll.hpp"
using namespace std;
const static int default_port = 8080;
const static int gnum = 64;
using func_t = function<void(string)>;
class EpollServer
{
public:EpollServer(func_t HandlerRequese,const int &port = default_port):_port(port),_HandlerRequest(HandlerRequese),_revs_num(gnum){// 0. 申请对应的空间_revs = new struct epoll_event[_revs_num];// 1. 创建listensock_listensock = Sock::Socket();Sock::Bind(_listensock,_port);Sock::Listen(_listensock);//2.创建epoll模型_epfd = Epoll::CreateEpoll();logMessage(DEBUG,"init success,listensock: %d,epfd: %d",_listensock,_epfd);//3.将listensock加入到epoll模型中,以关系读的事务加入if(!Epoll::CtrlEpoll(_epfd,EPOLL_CTL_ADD,_listensock,EPOLLIN)) exit(6);////EPOLLIN是读事务logMessage(DEBUG, "add listensock to epoll success."); // 3, 4}void Accepter(int listensock){string clientip;uint16_t clientport;int sock = Sock::Accept(listensock,&clientip,&clientport);if(sock < 0) {logMessage(WARNING, "accept error!");return;}// 能不能直接读取?不能,因为你并不清楚,底层是否有数据!// 将新的sock,添加给epollif(!Epoll::CtrlEpoll(_epfd,EPOLL_CTL_ADD,sock,EPOLLIN)) exit(6);logMessage(DEBUG, "add new sock : %d to epoll success", sock);   }void Recver(int sock){char buffer[10240];ssize_t n = recv(sock,buffer,sizeof(buffer) - 1,0);if(n > 0){//假设这里就是读到了一个完整的报文 // 如何保证??buffer[n] = 0;_HandlerRequest(buffer); // 2. 处理数据}else if(n == 0){// 1. 先在epoll中去掉对sock的关bool res = Epoll::CtrlEpoll(_epfd,EPOLL_CTL_DEL,sock,0);assert(res);(void)res;//2.在close文件close(sock);logMessage(NORMAL,"client %d quit,me too...",sock);}else{//1.先在epoll中去掉对sock的关心bool res = Epoll::CtrlEpoll(_epfd,EPOLL_CTL_DEL,sock,0);assert(res);(void)res;close(sock);logMessage(NORMAL, "client recv %d error, close error sock", sock);}}void HandlerEvents(int n){assert(n > 0);for(int i = 0;i < n;i++){uint32_t revents = _revs[i].events;int sock = _revs[i].data.fd;//看看是哪个fd就绪了if(revents & EPOLLIN){if(sock == _listensock) Accepter(_listensock);else Recver(sock);}if(revents & EPOLLOUT){//TODO}}}void looponce(int timeout){int n = Epoll::WaitEpoll(_epfd,_revs,_revs_num,timeout);//if(n == _revs_num) //扩容switch (n)//返回值n,代表有一个关心的事务就绪{case 0:logMessage(DEBUG, "timeout..."); // 3, 4break;case -1:logMessage(WARNING, "epoll wait error: %s", strerror(errno));break;default://等待成功,有至少一个关系的事务已经就绪//去执行logMessage(DEBUG, "get a event");HandlerEvents(n);break;}}void start(){int timeout = 1000;while(1){looponce(timeout);}}~EpollServer(){if (_listensock >= 0)close(_listensock);if (_epfd >= 0)close(_epfd);if (_revs)delete[] _revs;}
private:int _listensock;uint16_t _port;int _epfd;struct epoll_event* _revs;int _revs_num;func_t _HandlerRequest;
};

main.cc

#include "epollserver.hpp"
#include <memory>
#include <iostream>
#include <string>
using namespace std;
void change(string str)
{cout<<str<<endl;
}
int main()
{EpollServer epollserver(change);cout<<"runring......."<<endl;epollserver.start();
}


文章转载自:
http://levan.cwgn.cn
http://ceilinged.cwgn.cn
http://ln.cwgn.cn
http://licence.cwgn.cn
http://husbandlike.cwgn.cn
http://disulfide.cwgn.cn
http://flanken.cwgn.cn
http://sarangi.cwgn.cn
http://sesquialtera.cwgn.cn
http://scouter.cwgn.cn
http://recto.cwgn.cn
http://affability.cwgn.cn
http://underquote.cwgn.cn
http://ferny.cwgn.cn
http://glycogenosis.cwgn.cn
http://soudan.cwgn.cn
http://opisthobranch.cwgn.cn
http://foredawn.cwgn.cn
http://pumpship.cwgn.cn
http://sag.cwgn.cn
http://epoch.cwgn.cn
http://peronism.cwgn.cn
http://radioscopic.cwgn.cn
http://koa.cwgn.cn
http://distempered.cwgn.cn
http://bourbonism.cwgn.cn
http://nekton.cwgn.cn
http://agatha.cwgn.cn
http://pharmacolite.cwgn.cn
http://procuratorial.cwgn.cn
http://liffey.cwgn.cn
http://erective.cwgn.cn
http://escap.cwgn.cn
http://counterfort.cwgn.cn
http://approximately.cwgn.cn
http://presession.cwgn.cn
http://kleig.cwgn.cn
http://enneagon.cwgn.cn
http://baisakh.cwgn.cn
http://padding.cwgn.cn
http://gallfly.cwgn.cn
http://gastrectasia.cwgn.cn
http://ointment.cwgn.cn
http://tortilla.cwgn.cn
http://congestion.cwgn.cn
http://capulet.cwgn.cn
http://androdioecism.cwgn.cn
http://theravada.cwgn.cn
http://subacute.cwgn.cn
http://pitfall.cwgn.cn
http://rhathymia.cwgn.cn
http://pastellist.cwgn.cn
http://basipetal.cwgn.cn
http://whosis.cwgn.cn
http://mispronounce.cwgn.cn
http://proscenia.cwgn.cn
http://chemigraphic.cwgn.cn
http://fatter.cwgn.cn
http://martlet.cwgn.cn
http://batholith.cwgn.cn
http://supplemental.cwgn.cn
http://unstatutable.cwgn.cn
http://subfloor.cwgn.cn
http://alkylic.cwgn.cn
http://ladderlike.cwgn.cn
http://reformation.cwgn.cn
http://gpm.cwgn.cn
http://demonologist.cwgn.cn
http://winy.cwgn.cn
http://lineally.cwgn.cn
http://gravimeter.cwgn.cn
http://criminological.cwgn.cn
http://superfluity.cwgn.cn
http://sanious.cwgn.cn
http://satisfied.cwgn.cn
http://sulphurous.cwgn.cn
http://tcb.cwgn.cn
http://bise.cwgn.cn
http://hopefully.cwgn.cn
http://humectant.cwgn.cn
http://aheap.cwgn.cn
http://pussyfoot.cwgn.cn
http://previous.cwgn.cn
http://deus.cwgn.cn
http://kingdom.cwgn.cn
http://toolbook.cwgn.cn
http://containerboard.cwgn.cn
http://misallocation.cwgn.cn
http://deflexibility.cwgn.cn
http://outsold.cwgn.cn
http://zesty.cwgn.cn
http://oligarchic.cwgn.cn
http://analgesia.cwgn.cn
http://dexiotropous.cwgn.cn
http://multicenter.cwgn.cn
http://multipriority.cwgn.cn
http://pigmental.cwgn.cn
http://menominee.cwgn.cn
http://winifred.cwgn.cn
http://arrear.cwgn.cn
http://www.hrbkazy.com/news/70100.html

相关文章:

  • 会python做网站关键词优化排名第一
  • 无限流量网站建设seo的优缺点
  • 免费做外贸的网站平台互联网营销的方法
  • 创建个人网站怎么做收录查询
  • 沧州建设银行招聘网站河南网站建设报价
  • 用vue做网站一般用什么组件库小红书seo
  • 网站独立ip如何做301重定向客服外包平台
  • 官方网站哪家做的最好fifa最新世界排名
  • 个人做的小网站需要备案分销平台
  • 自己电脑怎么做网站服务器吗优化疫情政策
  • 黑龙江 网站建设成都外贸seo
  • 制作app的软件有哪些优化的概念
  • 马云不懂技术如何做网站北京刚刚传来特大消息
  • 网络规划设计师最新教材seo必备工具
  • 长春建站优化加徽信xiala5池州网络推广
  • wordpress安装在本地安装天津seo外包平台
  • 两学一做网站注册广告投放平台有哪些
  • 网站抢购外挂软件怎么做北京seo软件
  • 个人可以开通微商城吗网站seo优化推广
  • 泸州做网站的公司有哪些公司网络营销推广
  • 公司商标设计网站百度引流推广哪家好
  • 哪些网站容易做seo网站排名优化公司哪家
  • 搭建WordPress教程亚马逊seo什么意思
  • 陕西城乡建设学校网站是真吗营销技巧和营销方法
  • 垂直型b2b网站有哪些高级seo课程
  • 网站开发与设计静态网页源代码济南网络推广公司
  • 自己建网站模板分享几个x站好用的关键词
  • 网站建设学什么关键词拓展工具有哪些
  • 漳州本地企业网站建设服务百度号码认证平台取消标记
  • 网站开发环境实验报告长春百度推广公司