最简单的tcp服务,一次只能处理一个请求,请求处理完就直接关闭连接。这里只为了展示并发编程的逻辑,所以业务逻辑处理比较简单,就是接收客户端请求,打印客户端发送的信息。
tcp_server.h头文件
#ifndef TCP_SERVER_H_
#define TCP_SERVER_H_
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <thread>
#include <pthread.h>
#include <string>
#include <mutex>
#include <unistd.h>
#include "logger.h"
//using namespace std;
#define MAXLINE 4096
class Server{
public:
Server(string ip, int port){
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(ip.c_str());
}
virtual int start();
int connectionWorker();
bool init(logger *log);
protected:
sockaddr_in addr;
static logger *m_log;
};
#endif
tcp_server.cpp实现文件
#include <iostream>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <thread>
#include <string>
#include <mutex>
#include "tcp_server.h"
#include "logger.h"
logger* Server::m_log = NULL;
int Server::start(){
int sockfd,connfd;
struct sockaddr_in cliaddr;
socklen_t clilen;
char buff[MAXLINE];
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
m_log->outputLog("socket create failed: error %s, errno:%d",strerror(errno),errno);
return 0;
}
m_log->outputLog("socket create %d", sockfd);
int ret = ::bind(sockfd, (struct sockaddr*) &addr, sizeof(addr));
if(ret == -1){
m_log->outputLog("bind socket error: %s, errno:%d",strerror(errno),errno);
return 0;
}
if((listen(sockfd,10)) == -1){
m_log->outputLog("listen error: %s, errno:%s",strerror(errno),errno);
return 0;
}
//socklen_t len = sizeof(cliaddr);
while(true){
socklen_t len = sizeof(cliaddr);
if((connfd = accept(sockfd,(struct sockaddr*)&cliaddr,&len)) == -1){
m_log->outputLog("accept error: %s, errno:%s",strerror(errno),errno);
continue;
}
int n = recv(connfd,buff,MAXLINE,MSG_DONTWAIT);
buff[n] = '\0';
m_log->outputLog("recv msg:%s\n",buff);
close(connfd);
}
close(sockfd);
}
bool Server::init(logger *log){
if(log != NULL){
m_log = log;
return true;
}
return false;
}
int Server::connectionWorker(){
}
简单的日志类的实现
日志类头文件logger.h
#ifndef LOGGER_H_
#define LOGGER_H_
#include <iostream>
#include <sstream>
#include <string>
#include <stdio.h>
//#include <mutex>
using namespace std;
class logger{
public:
~logger();
void closeFd();
static logger* get_instance();
bool openLogFile(const string filepath, const string filename, bool bFlush);
void outputLog(const char *fmt, ...);
string getCurTime();
private:
static logger* m_instance;
static pthread_mutex_t m_log_mutex;
FILE * m_file_handler;
bool m_flush;
logger();
};
#endif
日志类实现文件logger.cpp,日志采用的是单例设计模式,类中声明的静态变量必须在类外单独初始化。
#include "logger.h"
#include <stdarg.h>
using namespace std;
pthread_mutex_t logger::m_log_mutex = PTHREAD_MUTEX_INITIALIZER;
logger* logger::m_instance = NULL;
logger::~logger(){
if(m_file_handler){
closeFd();
}
pthread_mutex_destroy(&m_log_mutex);
}
logger::logger(){
m_file_handler = NULL;
m_flush = false;
pthread_mutex_init(&m_log_mutex,NULL);
}
void logger::closeFd(){
if(m_file_handler){
fclose(m_file_handler);
}
}
logger* logger::get_instance(){
if(m_instance == NULL){
pthread_mutex_lock(&m_log_mutex);
if(m_instance == NULL){
m_instance = new logger();
}
pthread_mutex_unlock(&m_log_mutex);
}
return m_instance;
}
bool logger::openLogFile(const string filepath, const string filename, bool bFlush){
m_flush = bFlush;
string fullname = filepath;
if(fullname.length() > 0){
if(fullname.substr(fullname.length()-1,1) != "/"){
fullname += "/";
}
}
m_file_handler = fopen((fullname + filename).c_str(),"a");
if(m_file_handler == NULL){
return false;
}
return true;
}
string logger::getCurTime(){
time_t timep;
time(&timep);
char tmp[64];
strftime(tmp, sizeof(tmp),"%Y-%m-%d %H:%M:%S",localtime(&timep));
return tmp;
}
void logger::outputLog(const char* fmt, ... ){
ostringstream ofmt;
string time_str = getCurTime();
ofmt << getCurTime() << "\t[INFO]\t";
va_list args;
va_start(args,fmt);
ofmt << fmt << "\n";
if(m_file_handler){
vfprintf(m_file_handler, ofmt.str().c_str(), args);
}
if(m_flush){
fflush(m_file_handler);
}
}
客户端程序tcp_client.cpp
#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <thread>
#include <string>
#include <string.h>
#include <mutex>
#include "logger.h"
using namespace std;
#define MAXLINE 4096
class Client{
public:
int run(int i);
Client(){}
~Client(){}
int init(string ip, int port);
int setLog(logger * log);
int exit();
private:
struct sockaddr_in servaddr;
logger * m_log;
bool m_exit;
};
int Client::run(int i){
int sockfd, n;
m_exit = true;
ostringstream tmp;
tmp << "I'm client " << i << " .";
string sendline = tmp.str();
if((sockfd = socket(AF_INET, SOCK_STREAM,0)) < 0){
m_log->outputLog("create socket error: %s(errno: %d)\n", strerror(errno), errno);
return -1;
}
if(connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){
m_log->outputLog("connect socket error: %s(errno: %d)\n", strerror(errno), errno);
return -1;
}
while(true){
m_log->outputLog("send %s",sendline.c_str());
if(send(sockfd, sendline.c_str(), sendline.length(), 0) < 0){
m_log->outputLog("send error: %s(errno: %d)\n", strerror(errno), errno);
return -1;
}
m_log->outputLog("sleep 1s");
sleep(1);
}
close(sockfd);
return 0;
}
int Client::init(string ip, int port){
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(port);
servaddr.sin_addr.s_addr = inet_addr(ip.c_str());
}
int Client::setLog(logger * log){
if(log != NULL){
m_log = log;
return 0;
}
return -1;
}
测试主程序
服务器程序
#include "logger.h"
#include "tcp_server.h"
#include "tcp_server_thread.h"
#include "tcp_server_process.h"
#include "tcp_server_epoll.h"
#include "tcp_server_libevent.h"
#include "tcp_server_threadpoolevent.h"
#include <signal.h>
#include <sys/wait.h>
using namespace std;
logger *m_log = logger::get_instance();
void func_wait(int signo){
pid_t pid;
int stat;
pid = wait(&stat);
m_log->outputLog("child %d exit\n",pid);
return;
}
void func_waitpid(int signo){
pid_t pid;
int stat;
while( (pid = waitpid(-1,&stat,WNOHANG)) > 0 ){
m_log->outputLog("child %d exit\n",pid);
}
return;
}
nt main(){
signal(SIGCHLD, &func_waitpid);
//logger *m_log = logger::get_instance();
m_log->openLogFile("./","test_server.log",true);
Server *m_server = new Server("111.206.73.111",12345);
//Server *m_server = new ThreadServer("111.206.73.111",12345);
//Server *m_server = new ProcessServer("111.206.73.111",12345);
//Server *m_server = new poolEventServer("111.206.73.111",12345);
m_server->init(m_log);
m_server->start();
}
客户端测试主程序
#include "logger.h"
#include "tcp_client.h"
#include <stdlib.h>
using namespace std;
int main(int argc, char **argv){
logger *m_log = logger::get_instance();
m_log->openLogFile("./","test_client.log",true);
Client *m_client = new Client();
m_client->init("111.206.73.111",12345);
m_client->setLog(m_log);
m_client->run(atoi(argv[1]));
}