Last active
August 29, 2015 14:23
-
-
Save hongruiqi/7a4a0e7ff74901ceb889 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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