小编个人主页详情<—请点击 小编个人gitee代码仓库<—请点击 linux系统编程专栏<—请点击 linux网络编程专栏<—请点击 倘若命中无此运,孤身亦可登昆仑,送给屏幕面前的读者朋友们和小编自己! 
目录
-
- 前言
- 一、前置知识
- 二、接口和原理讲解
- 三、poll版本的TCP服务器
- 四、poll的缺点
- 五、源代码
-
- Main.cc
- makefile
- PollServer.hpp
- Log.hpp
- Socket.hpp
- 总结
前言
【linux】高级IO,I/O多路转接之select,接口和原理讲解,select版本的TCP服务器逐步完善讲解——书接上文 详情请点击<——,本文会在上文的基础上进行讲解,所以对上文不了解的读者友友请点击前方的蓝字链接进行学习 本文由小编为大家介绍——【linux】高级IO,I/O多路转接之poll,接口和原理讲解,poll版本的TCP服务器
一、前置知识

二、接口和原理讲解




三、poll版本的TCP服务器
#include <iostream>
#include <sys/select.h>
#include <unistd.h>
#include "Log.hpp"
#include "Socket.hpp"
using namespace std;
static const uint16_t defaultport = 8080;
static const int fd_num_max = sizeof(fd_set) * 8;
int defaultfd = –1;
class SelectServer
{
public:
SelectServer(uint16_t port = defaultport)
:_port(port)
{
for(int i = 0; i < fd_num_max; i++)
{
fd_array[i] = defaultfd;
}
}
bool Init()
{
_listensock.Socket();
_listensock.Bind(_port);
_listensock.Listen();
return true;
}
void Accepter()
{
string clientip;
uint16_t clientport;
int sock = _listensock.Accept(&clientip, &clientport);
if(sock < 0)
return;
lg(Info, "accept success, %s:%d, sock fd: %d", clientip.c_str(), clientport, sock);
int pos = 1;
for(; pos < fd_num_max; pos++)
{
if(fd_array[pos] == defaultfd)
break;
}
if(pos == fd_num_max)
{
lg(Warning, "server is full, close %d now", sock);
close(sock);
}
else
{
fd_array[pos] = sock;
PrintFd();
}
}
void Recver(int fd, int pos)
{
char buffer[1024];
ssize_t n = read(fd, buffer, sizeof(buffer) – 1);
if(n > 0)
{
buffer[n – 1] = 0;
cout << "get a message: " << buffer << endl;
}
else if(n == 0)
{
lg(Info, "client quit, me too, close fd: %d", fd);
close(fd);
fd_array[pos] = defaultfd;
}
else
{
lg(Warning, "recv error, fd: %d", fd);
close(fd);
fd_array[pos] = defaultfd;
}
}
void Dispatcher(fd_set& rfds)
{
for(int i = 0; i < fd_num_max; i++)
{
int fd = fd_array[i];
if(fd == defaultfd)
continue;
if(FD_ISSET(fd, &rfds))
{
if(fd == _listensock.Fd())
{
Accepter(); // 连接管理器
}
else
{
Recver(fd, i); // 数据读取器
}
}
}
}
void Start()
{
int listensock = _listensock.Fd();
fd_array[0] = listensock;
for(;;)
{
fd_set rfds;
FD_ZERO(&rfds);
int maxfd = fd_array[0];
for(int i = 0; i < fd_num_max; i++)
{
if(fd_array[i] != defaultfd)
{
FD_SET(fd_array[i], &rfds);
if(maxfd < fd_array[i])
{
maxfd = fd_array[i];
lg(Info, "max fd update, max fd is: %d", maxfd);
}
}
}
// struct timeval timeout = {2, 0};
struct timeval timeout = {0, 0};
// int n = select(listensock + 1, &rfds, nullptr, nullptr, &timeout);
// int n = select(listensock + 1, &rfds, nullptr, nullptr, nullptr);
int n = select(maxfd + 1, &rfds, nullptr, nullptr, nullptr);
switch(n)
{
case 0:
cout << "time out, timeout: " << timeout.tv_sec << "." << timeout.tv_usec << endl;
break;
case –1:
cout << "select error" << endl;
break;
default:
cout << "get a new link" << endl;
Dispatcher(rfds);
break;
}
}
}
void PrintFd()
{
cout << "online fd list: ";
for(int i = 0; i < fd_num_max; i++)
{
if(fd_array[i] != defaultfd)
{
cout << fd_array[i] << ' ';
}
}
cout << endl;
}
~SelectServer()
{
_listensock.Close();
}
private:
Sock _listensock;
uint16_t _port;
int fd_array[fd_num_max];
};

#include "PollServer.hpp"
#include <memory>
int main()
{
unique_ptr<PollServer> svr(new PollServer());
svr->Init();
svr->Start();
return 0;
}
#include <iostream>
#include <sys/select.h>
#include <unistd.h>
#include <poll.h>
#include "Log.hpp"
#include "Socket.hpp"
using namespace std;
static const uint16_t defaultport = 8080;
static const int fd_num_max = 64;
int defaultfd = –1;
int non_event = 0;
class PollServer
{
public:
PollServer(uint16_t port = defaultport)
:_port(port)
{
for(int i = 0; i < fd_num_max; i++)
{
_event_fds[i].fd = defaultfd;
_event_fds[i].events = non_event;
_event_fds[i].revents = non_event;
}
}
bool Init()
{
_listensock.Socket();
_listensock.Bind(_port);
_listensock.Listen();
return true;
}
void Accepter();
void Recver(int fd, int pos);
void Dispatcher(fd_set& rfds);
void Start();
void PrintFd();
~PollServer()
{
_listensock.Close();
}
private:
Sock _listensock;
uint16_t _port;
struct pollfd _event_fds[fd_num_max];
};

void Dispatcher()
{
for(int i = 0; i < fd_num_max; i++)
{
int fd = _event_fds[i].fd;
if(fd == defaultfd)
continue;
if(_event_fds[i].revents & POLLIN)
{
if(fd == _listensock.Fd())
{
Accepter(); // 连接管理器
}
else
{
Recver(fd, i); // 数据读取器
}
}
}
}
void Start()
{
_event_fds[0].fd = _listensock.Fd();
_event_fds[0].events = POLLIN;
int timeout = 3000;
for(;;)
{
int n = poll(_event_fds, fd_num_max, timeout);
switch(n)
{
case 0:
cout << "time out…" << endl;
break;
case –1:
cout << "poll error" << endl;
break;
default:
cout << "get a new link" << endl;
Dispatcher();
break;
}
}
}
void Accepter()
{
string clientip;
uint16_t clientport;
int sock = _listensock.Accept(&clientip, &clientport);
if(sock < 0)
return;
lg(Info, "accept success, %s:%d, sock fd: %d", clientip.c_str(), clientport, sock);
int pos = 1;
for(; pos < fd_num_max; pos++)
{
if(_event_fds[pos].fd == defaultfd)
break;
}
if(pos == fd_num_max)
{
lg(Warning, "server is full, close %d now", sock);
close(sock);
// 扩容
}
else
{
_event_fds[pos].fd = sock;
_event_fds[pos].events = POLLIN;
_event_fds[pos].revents = non_event;
PrintFd();
}
}
void PrintFd()
{
cout << "online fd list: ";
for(int i = 0; i < fd_num_max; i++)
{
if(_event_fds[i].fd != defaultfd)
{
cout << _event_fds[i].fd << ' ';
}
}
cout << endl;
}
void Recver(int fd, int pos)
{
char buffer[1024];
ssize_t n = read(fd, buffer, sizeof(buffer) – 1);
if(n > 0)
{
buffer[n – 1] = 0;
cout << "get a message: " << buffer << endl;
}
else if(n == 0)
{
lg(Info, "client quit, me too, close fd: %d", fd);
close(fd);
_event_fds[pos].fd = defaultfd;
}
else
{
lg(Warning, "recv error, fd: %d", fd);
close(fd);
_event_fds[pos].fd = defaultfd;
}
}
运行结果如下 
四、poll的缺点
五、源代码
Main.cc
#include "PollServer.hpp"
#include <memory>
int main()
{
unique_ptr<PollServer> svr(new PollServer());
svr->Init();
svr->Start();
return 0;
}
makefile
pollserver:Main.cc
g++ -o $@ $^ -std=c++11
.PHONY:clean
clean:
rm -f pollserver
PollServer.hpp
#include <iostream>
#include <sys/select.h>
#include <unistd.h>
#include <poll.h>
#include "Log.hpp"
#include "Socket.hpp"
using namespace std;
static const uint16_t defaultport = 8080;
static const int fd_num_max = 64;
int defaultfd = –1;
int non_event = 0;
class PollServer
{
public:
PollServer(uint16_t port = defaultport)
:_port(port)
{
for(int i = 0; i < fd_num_max; i++)
{
_event_fds[i].fd = defaultfd;
_event_fds[i].events = non_event;
_event_fds[i].revents = non_event;
}
}
bool Init()
{
_listensock.Socket();
_listensock.Bind(_port);
_listensock.Listen();
return true;
}
void Accepter()
{
string clientip;
uint16_t clientport;
int sock = _listensock.Accept(&clientip, &clientport);
if(sock < 0)
return;
lg(Info, "accept success, %s:%d, sock fd: %d", clientip.c_str(), clientport, sock);
int pos = 1;
for(; pos < fd_num_max; pos++)
{
if(_event_fds[pos].fd == defaultfd)
break;
}
if(pos == fd_num_max)
{
lg(Warning, "server is full, close %d now", sock);
close(sock);
// 扩容
}
else
{
_event_fds[pos].fd = sock;
_event_fds[pos].events = POLLIN;
_event_fds[pos].revents = non_event;
PrintFd();
}
}
void Recver(int fd, int pos)
{
char buffer[1024];
ssize_t n = read(fd, buffer, sizeof(buffer) – 1);
if(n > 0)
{
buffer[n – 1] = 0;
cout << "get a message: " << buffer << endl;
}
else if(n == 0)
{
lg(Info, "client quit, me too, close fd: %d", fd);
close(fd);
_event_fds[pos].fd = defaultfd;
}
else
{
lg(Warning, "recv error, fd: %d", fd);
close(fd);
_event_fds[pos].fd = defaultfd;
}
}
void Dispatcher()
{
for(int i = 0; i < fd_num_max; i++)
{
int fd = _event_fds[i].fd;
if(fd == defaultfd)
continue;
if(_event_fds[i].revents & POLLIN)
{
if(fd == _listensock.Fd())
{
Accepter(); // 连接管理器
}
else
{
Recver(fd, i); // 数据读取器
}
}
}
}
void Start()
{
_event_fds[0].fd = _listensock.Fd();
_event_fds[0].events = POLLIN;
int timeout = 3000;
for(;;)
{
int n = poll(_event_fds, fd_num_max, timeout);
switch(n)
{
case 0:
cout << "time out…" << endl;
break;
case –1:
cout << "poll error" << endl;
break;
default:
cout << "get a new link" << endl;
Dispatcher();
break;
}
}
}
void PrintFd()
{
cout << "online fd list: ";
for(int i = 0; i < fd_num_max; i++)
{
if(_event_fds[i].fd != defaultfd)
{
cout << _event_fds[i].fd << ' ';
}
}
cout << endl;
}
~PollServer()
{
_listensock.Close();
}
private:
Sock _listensock;
uint16_t _port;
struct pollfd _event_fds[fd_num_max];
};
Log.hpp
#pragma once
#include <iostream>
#include <string>
#include <ctime>
#include <cstdio>
#include <cstdarg>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define SIZE 1024
#define Info 0
#define Debug 1
#define Warning 2
#define Error 3
#define Fatal 4
#define Screen 1 //输出到屏幕上
#define Onefile 2 //输出到一个文件中
#define Classfile 3 //根据事件等级输出到不同的文件中
#define LogFile "log.txt" //日志名称
class Log
{
public:
Log()
{
printMethod = Screen;
path = "./log/";
}
void Enable(int method) //改变日志打印方式
{
printMethod = method;
}
~Log()
{}
std::string levelToString(int level)
{
switch(level)
{
case Info:
return "Info";
case Debug:
return "Debug";
case Warning:
return "Warning";
case Error:
return "Error";
case Fatal:
return "Fatal";
default:
return "";
}
}
void operator()(int level, const char* format, ...)
{
//默认部分 = 日志等级 + 日志时间
time_t t = time(nullptr);
struct tm* ctime = localtime(&t);
char leftbuffer[SIZE];
snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", levelToString(level).c_str(),
ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday,
ctime->tm_hour, ctime->tm_min, ctime->tm_sec);
va_list s;
va_start(s, format);
char rightbuffer[SIZE];
vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);
va_end(s);
char logtxt[2 * SIZE];
snprintf(logtxt, sizeof(logtxt), "%s %s", leftbuffer, rightbuffer);
printLog(level, logtxt);
}
void printLog(int level, const std::string& logtxt)
{
switch(printMethod)
{
case Screen:
std::cout << logtxt << std::endl;
break;
case Onefile:
printOneFile(LogFile, logtxt);
break;
case Classfile:
printClassFile(level, logtxt);
break;
default:
break;
}
}
void printOneFile(const std::string& logname, const std::string& logtxt)
{
std::string _logname = path + logname;
int fd = open(_logname.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666);
if(fd < 0)
return;
write(fd, logtxt.c_str(), logtxt.size());
close(fd);
}
void printClassFile(int level, const std::string& logtxt)
{
std::string filename = LogFile;
filename += ".";
filename += levelToString(level);
printOneFile(filename, logtxt);
}
private:
int printMethod;
std::string path;
};
Log lg;
Socket.hpp
#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Log.hpp"
const int backlog = 10;
enum{
SocketErr = 1,
BindErr,
ListenErr,
};
class Sock
{
public:
Sock()
{}
void Socket()
{
sockfd_ = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd_ < 0)
{
lg(Fatal, "socket error, %s : %d", strerror(errno), errno);
exit(SocketErr);
}
int opt = 1;
setsockopt(sockfd_, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt));
}
void Bind(uint16_t port)
{
struct sockaddr_in local;
memset(&local, 0, sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = INADDR_ANY;
socklen_t len = sizeof(local);
if(bind(sockfd_, (struct sockaddr*)&local, len) < 0)
{
lg(Fatal, "bind error, %s : %d", strerror(errno), errno);
exit(BindErr);
}
}
void Listen()
{
if(listen(sockfd_, backlog) < 0)
{
lg(Fatal, "listen error, %s : %d", strerror(errno), errno);
exit(ListenErr);
}
}
int Accept(std::string* clientip, uint16_t* clientport)
{
struct sockaddr_in peer;
socklen_t len = sizeof(peer);
int newfd = accept(sockfd_, (struct sockaddr*)&peer, &len);
if(newfd < 0)
{
lg(Warning, "accept error, %s : %d", strerror(errno), errno);
return –1;
}
char ipstr[128];
inet_ntop(AF_INET, &(peer.sin_addr), ipstr, sizeof(ipstr));
*clientip = ipstr;
*clientport = ntohs(peer.sin_port);
return newfd;
}
bool Connect(const std::string& serverip, uint16_t serverport)
{
struct sockaddr_in peer;
memset(&peer, 0, sizeof(peer));
peer.sin_family = AF_INET;
peer.sin_port = htons(serverport);
inet_pton(AF_INET, serverip.c_str(), &(peer.sin_addr));
socklen_t len = sizeof(peer);
int n = connect(sockfd_, (struct sockaddr*)&peer, len);
if(n == –1)
{
std::cerr << "connect to " << serverip << ':' << serverport << "error" << std::endl;
return false;
}
return true;
}
void Close()
{
if(sockfd_ > 0)
{
close(sockfd_);
}
}
int Fd()
{
return sockfd_;
}
~Sock()
{}
private:
int sockfd_;
};
总结
以上就是今天的博客内容啦,希望对读者朋友们有帮助 水滴石穿,坚持就是胜利,读者朋友们可以点个关注 点赞收藏加关注,找到小编不迷路!
网硕互联帮助中心



评论前必须登录!
注册