【Linux網路程式設計-5】多執行緒服務端

徘徊彼岸花發表於2024-07-10
//mthserver.cpp
#include "TcpServer.h"
#include "CLogFile.h"
#include <string>
#include <pthread.h>
#include <vector>

CLogFile logfile;
TcpServer tcpServer;
std::vector<long> vpthids;	//儲存執行緒id

void mainEXIT(int sig)
{
    if(sig>0)	
    {
        signal(sig,SIG_IGN);
        signal(SIGINT,SIG_IGN);
        signal(SIGTERM,SIG_IGN);
        
        printf("mthserver exit..(PID=%d)\n",getpid());
        logfile.Write("mthserver exit..(PID=%d)\n",getpid());

        tcpServer.CloseListen();
        for(auto& pthid:vpthids)
        {
          pthread_cancel(pthid);
        }
        std::vector<long>(0).swap(vpthids);
        exit(0);
    }
}

void pthExit(void* arg)
{
    int sockfd=(int)(long)arg;
    close(sockfd);

    for(auto iter=vpthids.begin();iter!=vpthids.end();iter++)
    {
      if(*iter==pthread_self())
        vpthids.erase(iter);
    }

    logfile.Write("thread clean..\n") ;
}

bool biz002(const char* strRecvBuffer,char* strSendBuffer)
{
    char msg[1024];
    memset(msg,0,sizeof(msg));
    GetXmlBuffer(strRecvBuffer,"message",msg,1023);
    
    strcat(msg,"	ok");
    sprintf(strSendBuffer,"<retcode>0</retcode><message>%s</message>",msg);
    return true;
}


//業務1(business001)處理函式
bool biz001(const char* strRecvBuffer,char* strSendBuffer)
{
    //從strRecvBuffer中解析出username欄位和password欄位的值
    char username[51],password[51];
    memset(username,0,sizeof(username));
    memset(password,0,sizeof(password));
    
    GetXmlBuffer(strRecvBuffer,"username",username,50);
    GetXmlBuffer(strRecvBuffer,"password",password,50);
    
    //將使用者名稱、密碼同資料庫中值對比
    if((strcmp(username, "wk")==0)&&(strcmp(password, "p@ssw0rd")==0))
        sprintf(strSendBuffer,"<retcode>0</retcode><message>login success</message>");
    else
        sprintf(strSendBuffer,"<retcode>-1</retcode><message>使用者名稱或密碼不正確</message>");
    
    return true;
}

//心跳響應
bool biz000(const char* strRecvBuffer,char* strSendBuffer)
{
    sprintf(strSendBuffer, "<retcode>0</retcode><message>heartbeat success</message>");
    return true;
}

//業務處理函式
//strRecvBuffer-接收報文
//strSendBuffer-傳送報文
bool BusinessProcess(const char* strRecvBuffer,char* strSendBuffer)
{
    int ibizcode=-1;
    GetXmlBuffer(strRecvBuffer,"bizcode",&ibizcode);
    
    switch(ibizcode)
    {
        case 0:
            return biz000(strRecvBuffer,strSendBuffer);	//心跳
            break;
        case 1:
            return biz001(strRecvBuffer,strSendBuffer);	//登入
            break;
        case 2:
            return biz002(strRecvBuffer,strSendBuffer);	//業務2
            break;
        default:
            logfile.Write("非法報文:%s\n",strSendBuffer);
            return false;
    }
}

void* thmainfunc(void* arg)
{
    pthread_detach(pthread_self());
    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
    pthread_cleanup_push(pthExit,arg);

    char strRecvBuffer[1024];
    char strSendBuffer[1024];
    int sockfd=(int)(long)arg;
    while(true)
    {
        memset(strRecvBuffer,0,sizeof(strRecvBuffer));
       	memset(strSendBuffer,0,sizeof(strSendBuffer));
        int iBufferlen;
        if(tcpServer.TcpRead(sockfd,strRecvBuffer, &iBufferlen,300)==false)  //超過60s沒有收到心跳報文,就斷開連線
            break;
        logfile.Write("recv msg:%s\n",strRecvBuffer);
        
        //業務處理
        if(BusinessProcess(strRecvBuffer,strSendBuffer)==false)
          pthread_exit(0);
        
       	logfile.Write("send msg:%s\n",strSendBuffer);
        if(tcpServer.TcpWrite(sockfd,strSendBuffer)==false)   
            break;
    }
    
    logfile.Write("client(%s) disconnected..\n", tcpServer.GetIP());
    pthread_cleanup_pop(1);
    pthread_exit(0);
}


int main(int argc, char** argv)
{
 	if(argc!=3)	
    {
        printf("Using: ./mthserver port logfile\nExample:./mthserver 5000 /tmp/mthserver.log\n\n");
        return -1;
    }
   
    for(int i=0;i<70;i++)
    {
        signal(i, SIG_IGN);
    }

    logfile.m_bBackup=false; //多程序服務程式關閉日誌切換

    if(logfile.Open(argv[2], "a+") == false)	//a+新增,不存在則建立
    {
        printf("logfile open failed..(%s)\n", argv[2]);
    }
    
    signal(SIGINT,mainEXIT);	
    signal(SIGTERM,mainEXIT);
    if(tcpServer.InitServer(atoi(argv[1]))==false)
    {
        logfile.Write("server init failed..\n");
        mainEXIT(-1);
    }

    while(true)
    {
        if(tcpServer.Accept()==false)
        {
            logfile.Write("client(%s) connected failed..\n", tcpServer.GetIP());
            continue;	
        }
        logfile.Write("client(%s) connected..\n", tcpServer.GetIP());

        pthread_t pthid;
        if(pthread_create(&pthid,NULL,thmainfunc,(void*)(long)tcpServer.m_clientfd)!=0)
        {
          logfile.Write("create thread failed..\n");
          return -1;
        }
        vpthids.push_back(pthid);
    }
    return 0;
}

相關文章