【C++ TCP服务器类--带心跳检测】

1.TCP服务器类封装

#ifndef _TCP_SERVER_H_
#define _TCP_SERVER_H_

#include <string>
#ifdef __cplusplus
extern "C" {
#endif

#define TCP_PORT_NO                 8888 //端口号
#define TCP_BUFFER_SIZE             (4*1024) //4k
#define HEART_BEAT_INTERVAL         (15) //心跳间隔15s

class Tcp_Server
{
private:
    static Tcp_Server *g_object;
    Tcp_Server();
    ~Tcp_Server();

private:
    static void* tcp_socket_thread_loop(void* data);
    static void* tcp_socket_beat_thread_loop(void *data);
    void handle_request(int sockfd);

private:
    pthread_t   m_socketThread;
    pthread_t   m_socketBeatThread;
    int m_sockFd;
    int m_connectSockFd;
    bool m_run;

public:
    static Tcp_Server * get(void);
    int start_tcp_server();
    int stop_tcp_server(); 
};

#ifdef __cplusplus
}
#endif

#endif

2.构建单例模式

Tcp_Server* Tcp_Server::g_object = NULL;

Tcp_Server* Tcp_Server::get(void)
{
    if(NULL == g_object)
    {
        g_object = new Tcp_Server;
    } 
    return g_object;
}

3.创建TCP服务器

int Tcp_Server::start_tcp_server()
{
    m_sockFd = socket(AF_INET, SOCK_STREAM, 0);
    if (m_sockFd < 0) {
        printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
        return -1;
    }

    // set SO_REUSEADDR on a socket to true
    int optval = 1;
    int ret = setsockopt(m_sockFd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
    if (ret < 0)
    {
        printf("Error setting socket option ret:%d\n",ret);
        return -1;
    }

    struct sockaddr_in serverAddr;
    memset(&serverAddr, 0, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = INADDR_ANY;
    serverAddr.sin_port = htons(TCP_PORT_NO);
    if (bind(m_sockFd, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) < 0)
    {
        printf("Binding error: please try again in 20sec and make sure no other instance is running\n");
        return -1;
    }

    if (-1 == listen(m_sockFd, 10)) 
    {
        printf("listen socket error: %s(errno: %d)\n", strerror(errno), errno);
        return -1;
    }
    printf("success to create tcp server...\n");
    m_run = true;

    pthread_create(&m_socketThread, NULL, tcp_socket_thread_loop, this);
    if (!m_socketThread) {
        printf("create m_socketThread failed");
        return -1;
    }

    pthread_create(&m_socketBeatThread, NULL,tcp_socket_beat_thread_loop,this);
    if (!m_socketBeatThread) {
        printf("create m_socketBeatThread failed");
        return -1;
    }

    return 0;
}

4.客户端请求处理线程

void* Tcp_Server::tcp_socket_thread_loop(void *data)
{
    Tcp_Server *service = (Tcp_Server *)data;
    while (service->m_run) 
    {
        if (service->m_connectSockFd < 0)
        {
            struct sockaddr_in clientAddr;
            socklen_t clientLen = sizeof(clientAddr);
            //收到客户端连接后,后续都用连接描述符通信
            service->m_connectSockFd = accept(service->m_sockFd, (struct sockaddr *)&clientAddr, &clientLen);
            if (service->m_connectSockFd < 0) 
            {
                printf("couldn't accept\n");
                continue; 
            }
            else{
                service->handle_request(service->m_connectSockFd);
            }
        }
        else{
        	service->handle_request(service->m_connectSockFd);
        }
        usleep(1000);
    }
	return NULL;
}

5.心跳线程维持连接

void* Tcp_Server::tcp_socket_beat_thread_loop(void *data)
{
    Tcp_Server *service = (Tcp_Server *)data;
	size_t send_size = 0
    while (service->m_run) 
    {
        if (service->m_connectSockFd >= 0) 
        {
            std::string beat = "action:heart beat";
            send_size  = send(service->m_connectSockFd, beat.c_str(), beat.size(), MSG_NOSIGNAL);
            if(send_size == -1)
            {
            	close(m_service->m_connectSockFd);
            	service->m_connectSockFd = -1;
            	printf("client is disconnected...\n");
            }
            else{
            	printf("send client:%s\n",beat.c_str());
            }  
        }
        sleep(HEART_BEAT_INTERVAL);
    }
	return NULL;
}

6.客户端请求处理函数

void Tcp_Server::handle_request(int sockfd)
{
    char* read_buffer = new char[TCP_BUFFER_SIZE];

    int size = read(sockfd, read_buffer, TCP_BUFFER_SIZE);
    printf("recv client:%s\n",read_buffer);
    delete[] read_buffer;

    std::string response = "hello this is http server...";
    send(sockfd, response.c_str(), response.size(), MSG_NOSIGNAL);
    printf("send client:%s\n",response.c_str());
}

7.调试打印

1.客户端调试日志

在这里插入图片描述

2.服务端调试日志

在这里插入图片描述

8.源码如下

1.tcp_server.h源码

#ifndef _TCP_SERVER_H_
#define _TCP_SERVER_H_

#include <string>
#ifdef __cplusplus
extern "C" {
#endif

#define TCP_PORT_NO                 8888 //端口号
#define TCP_BUFFER_SIZE             (4*1024) //4k
#define HEART_BEAT_INTERVAL         (15) //心跳间隔15s

class Tcp_Server
{
private:
    static Tcp_Server *g_object;
    Tcp_Server();
    ~Tcp_Server();

private:
    static void* tcp_socket_thread_loop(void* data);
    static void* tcp_socket_beat_thread_loop(void *data);
    void handle_request(int sockfd);

private:
    pthread_t   m_socketThread;
    pthread_t   m_socketBeatThread;
    int m_sockFd;
    int m_connectSockFd;
    bool m_run;

public:
    static Tcp_Server * get(void);
    int start_tcp_server();
    int stop_tcp_server(); 
};

#ifdef __cplusplus
}
#endif

#endif

2.tcp_server.cpp源码

#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include "tcp_server.h"

Tcp_Server* Tcp_Server::g_object = NULL;

Tcp_Server* Tcp_Server::get(void)
{
    if(NULL == g_object)
    {
        g_object = new Tcp_Server;
    } 
    return g_object;
}

void Tcp_Server::handle_request(int sockfd)
{
    char* read_buffer = new char[TCP_BUFFER_SIZE];

    int size = read(sockfd, read_buffer, TCP_BUFFER_SIZE);
    printf("recv client:%s\n",read_buffer);
    delete[] read_buffer;

    std::string response = "hello this is http server...";
    send(sockfd, response.c_str(), response.size(), MSG_NOSIGNAL);
    printf("send client:%s\n",response.c_str());
}

void* Tcp_Server::tcp_socket_thread_loop(void *data)
{
    Tcp_Server *service = (Tcp_Server *)data;
    while (service->m_run) 
    {
        if (service->m_connectSockFd < 0)
        {
            struct sockaddr_in clientAddr;
            socklen_t clientLen = sizeof(clientAddr);
            //收到客户端连接后,后续都用连接描述符通信
            service->m_connectSockFd = accept(service->m_sockFd, (struct sockaddr *)&clientAddr, &clientLen);
            if (service->m_connectSockFd < 0) 
            {
                printf("couldn't accept\n");
                continue; 
            }
            else{
                service->handle_request(service->m_connectSockFd);
            }
        }
        else{
        	service->handle_request(service->m_connectSockFd);
        }
        usleep(1000);
    }
	return NULL;
}

void* Tcp_Server::tcp_socket_beat_thread_loop(void *data)
{
    Tcp_Server *service = (Tcp_Server *)data;

    while (service->m_run) 
    {
        if (service->m_connectSockFd >= 0) 
        {
            std::string beat = "action:heart beat";
            send(service->m_connectSockFd, beat.c_str(), beat.size(), MSG_NOSIGNAL);
            printf("send client:%s\n",beat.c_str());
        }
        sleep(HEART_BEAT_INTERVAL);
    }
	return NULL;
}

int Tcp_Server::stop_tcp_server()
{
    m_run = false;
    close(m_connectSockFd);//关闭通信fd
    close(m_sockFd);//关闭监听fd
    m_connectSockFd = -1;
    m_sockFd = -1;
    return 0;
}

int Tcp_Server::start_tcp_server()
{
    m_sockFd = socket(AF_INET, SOCK_STREAM, 0);
    if (m_sockFd < 0) {
        printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
        return -1;
    }

    // set SO_REUSEADDR on a socket to true
    int optval = 1;
    int ret = setsockopt(m_sockFd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
    if (ret < 0)
    {
        printf("Error setting socket option ret:%d\n",ret);
        return -1;
    }

    struct sockaddr_in serverAddr;
    memset(&serverAddr, 0, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = INADDR_ANY;
    serverAddr.sin_port = htons(TCP_PORT_NO);
    if (bind(m_sockFd, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) < 0)
    {
        printf("Binding error: please try again in 20sec and make sure no other instance is running\n");
        return -1;
    }

    if (-1 == listen(m_sockFd, 10)) 
    {
        printf("listen socket error: %s(errno: %d)\n", strerror(errno), errno);
        return -1;
    }
    printf("success to create tcp server...\n");
    m_run = true;

    pthread_create(&m_socketThread, NULL, tcp_socket_thread_loop, this);
    if (!m_socketThread) {
        printf("create m_socketThread failed");
        return -1;
    }

    pthread_create(&m_socketBeatThread, NULL,tcp_socket_beat_thread_loop,this);
    if (!m_socketBeatThread) {
        printf("create m_socketBeatThread failed");
        return -1;
    }

    return 0;
}

Tcp_Server::Tcp_Server()
{
    m_run = false;
    m_sockFd = -1;
    m_connectSockFd = -1;
}

Tcp_Server::~Tcp_Server()
{

}

3.main.cpp源码

#include "tcp_server.h"
#include <unistd.h>

int main()
{
    Tcp_Server::get()->start_tcp_server();
    while(1)
    {
        usleep(1000);
    }
    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值