Skip to content

Instantly share code, notes, and snippets.

@hongruiqi
Last active August 29, 2015 14:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hongruiqi/7a4a0e7ff74901ceb889 to your computer and use it in GitHub Desktop.
Save hongruiqi/7a4a0e7ff74901ceb889 to your computer and use it in GitHub Desktop.
#include <string>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cerrno>
#include <stdexcept>
#include <sys/wait.h>
class EchoHandler {
public:
void operator()(int fd) {
char buf[1024];
int n;
while ((n = read(fd, buf, 1024))>0) {
write(fd, buf, n);
}
close(fd);
}
};
template<typename TServer>
class AcceptTask {
public:
AcceptTask(TServer& server) : server_(server) {}
void operator()() {
server_.Accept();
}
private:
TServer& server_;
};
template<typename Task>
class ProcessPool {
public:
ProcessPool(int n, Task& task) : n_(n), task_(task) {
}
void Start() {
for (int i=0; i<n_; i++) {
int pid = fork();
if (pid>0) continue;
task_();
}
int status = 0;
for (int i=0; i<n_; i++) {
wait(&status);
}
}
private:
int n_;
Task& task_;
};
template<typename Handler>
class Server {
public:
Server(Handler& handler) : handler_(handler) {
fd_ = socket(AF_INET, SOCK_STREAM, 0);
if (fd_<0) {
throw std::runtime_error(strerror(errno));
}
}
void Bind(const std::string& addr, unsigned short port) {
sockaddr_in s_in;
bzero(&s_in, sizeof(s_in));
s_in.sin_family = AF_INET;
s_in.sin_addr.s_addr = inet_addr(addr.c_str());
s_in.sin_port = htons(port);
int on = 1;
if (bind(fd_, (struct sockaddr*)&s_in, sizeof(s_in))<0) {
throw std::runtime_error(strerror(errno));
}
if (setsockopt(fd_, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))<0) {
throw std::runtime_error(strerror(errno));
}
}
void Listen(int backlog) {
if (listen(fd_, backlog)<0) {
throw std::runtime_error(strerror(errno));
}
}
~Server() {
close(fd_);
}
void Accept() {
sockaddr_in s_in;
unsigned int size = sizeof(s_in);
while (true) {
int fd = accept(fd_, (struct sockaddr*)&s_in, &size);
if (fd<0) {
throw std::runtime_error(strerror(errno));
}
handler_(fd);
}
}
private:
int fd_;
Handler& handler_;
};
int main() {
EchoHandler echo_handler;
Server<EchoHandler> server(echo_handler);
server.Bind("0.0.0.0", 8000);
server.Listen(10);
AcceptTask<Server<EchoHandler> > task(server);
ProcessPool<AcceptTask<Server<EchoHandler> > > pool(10, task);
pool.Start();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment