client.cpp

/*********************************************************************************
Copyright (cpp) Novatek Microelectronics Corp, Ltd. All Rights Reserved.
\file client.cpp
\brief achieve two terninal communication
\for Liunx
\chip none
\Date 2024-08-22
\version v0.0.1
*********************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <time.h>
#include <signal.h>
#include "PrintLevel.h"

#define BUFFER_SIZE  (1024)
#define NAMESIZE     (50)
#define INITSOCKETE  (-1)
#define TIMENAMESIZE (20)
#define LOGNAMESIZE  (100)
#define MYPORT       (2222)
#define IP           ("127.0.0.1")

typedef unsigned int   u32;
typedef unsigned short u16;
typedef char           u8;
typedef int            s32;

s32 gPrintAPILevel                = EN_PRINTAPI_MSG;
static s32 giClientSocket         = INITSOCKETE;
static FILE *gpLogFile            = NULL;
static u8 gcUserName[NAMESIZE]    = {0};
static s32 iQuitNum               = 1;
static pthread_mutex_t gLogMutex  = PTHREAD_MUTEX_INITIALIZER;//Static initilization
static pthread_mutex_t gQuitMutex = PTHREAD_MUTEX_INITIALIZER;//Static initilization
volatile sig_atomic_t vsClientRun = 1;

typedef enum _EN_ERRO_RETURN
{
    EN_FGETS_FAIL       = -6,
    EN_NULL_POINTER     = -5,
    EN_CREATSOC_FAIL    = -4,
    EN_CONNSOC_FAIL     = -3,
    EN_THREAD_JOINFAIL  = -2,
    EN_THREAD_CREATFAIL = -1,
    EN_SUCCESS          = 0
}EN_ERRO_RETURN;

/*!
@brisf:Signal processing program, used to process SIGINT and SIGTERM signals

*@para[in] s32 iSigNum:
*@return void:
*/
void SigHandler(s32 iSigNum)
{
    PRINTAPI_TRC("Enter SigHandler API\n");
    PRINTAPI_DBG("Signum is %d\n", iSigNum);
    if(iSigNum == SIGINT)
    {
        PRINTAPI_ERR("Received signal Ctr+C, shutting down client...\n");
        vsClientRun = 0;
    }
    else if(iSigNum == SIGTERM)
    {
        PRINTAPI_ERR("Received signal Ctr+Z shutting down client...\n");
        vsClientRun = 0;
    }
    PRINTAPI_TRC("Out SigHandler API\n");
}

/*!
@brisf:log_message of user at different time

*@para[in] const u8 *message:comminication context

*@return void:
*/
void LogMess(const u8 *pMess)
{
    PRINTAPI_TRC("Enter LogMess API\n");
    time_t tCurrTime             = 0;
    struct tm *stpLocalTime      = NULL;
    u8 cTimeStr[TIMENAMESIZE]    = {0};
    u8 cLogFileName[LOGNAMESIZE] = {0};

    if(nullptr == pMess)
    {
        PRINTAPI_ERR("LogMess pMess is nullpointer\n");
        PRINTAPI_TRC("Out LogMess API\n");
        return;
    }
    PRINTAPI_DBG("LogMess pMess is %s\n", pMess);

    time(&tCurrTime);
    stpLocalTime = localtime(&tCurrTime);
    strftime(cTimeStr, sizeof(cTimeStr), "%Y-%m-%d %H:%M:%S", stpLocalTime);

    //Define log name using username and only socket id
    snprintf(cLogFileName, sizeof(cLogFileName), "chat_log_%s_%d.txt", gcUserName, giClientSocket);//Auto add '\0'

    pthread_mutex_lock(&gLogMutex);
    gpLogFile = fopen(cLogFileName, "a");
    if (gpLogFile == NULL)
    {
        PRINTAPI_ERR("LogMess pMess fopen gpLogFile fail\n");
        PRINTAPI_TRC("Out LogMess API\n");
        return;
    }
    fprintf(gpLogFile, "[%s]: %s\n", cTimeStr, pMess);//Not add '\0'
    fflush(gpLogFile);
    pthread_mutex_unlock(&gLogMutex);
    PRINTAPI_TRC("Out LogMess API\n");
}

/*!
@brisf:read_input:user input communication context

*@para[in] void *arg: NULL

*@return void*:
*/
void *ReadInput(void *pArg)
{
    PRINTAPI_TRC("Enter read_input API\n");
    s32 iClientSocket        = 0;//If pArg is not EN_NULL_POINTER and then give value to iClientSocket
    u8 cBuff[BUFFER_SIZE]    = {0};
    u8 cTmpBuff[BUFFER_SIZE] = {0};
    if(nullptr == pArg)
    {
        PRINTAPI_ERR("ReadInput API  pArg is nullpointer\n");
        return NULL;
    }
    iClientSocket = *(s32 *)pArg;//If pArg is not EN_NULL_POINTER and then give value to iClientSocket
    PRINTAPI_DBG("ReadInput API iClientSocket is %d\n", iClientSocket);
    PRINTAPI_MSG("\n*********Type 'quit' to exit*******\n");

    PRINTAPI_DBG("ReadInput API iQuitNum is %d . vsClientRun is %d \n", iQuitNum, vsClientRun);
    while(vsClientRun && iQuitNum)
    {
        memset(cBuff, 0, BUFFER_SIZE);
        memset(cTmpBuff, 0, BUFFER_SIZE);
        PRINTAPI_MSG("%s input : ", gcUserName);
        snprintf(cBuff, sizeof(cBuff), "%s: ", gcUserName);//Uername write to cBuff auto add "\0" end
        fgets(cTmpBuff, sizeof(cTmpBuff), stdin);
        cTmpBuff[strcspn(cTmpBuff, "\n")] = '\0'; //Remove '\n'

        if(0 == (strcmp(cTmpBuff,"quit")))
        {
            pthread_mutex_lock(&gQuitMutex);
            iQuitNum = 0;
            pthread_mutex_unlock(&gQuitMutex);
            continue;
        }

        strncat(cBuff,cTmpBuff,strlen(cTmpBuff));//Auto add '\0' at end
        cBuff[strlen(cBuff)] = '\0';
        PRINTAPI_MSG(" Send context : %s\n", cBuff);

        LogMess(cBuff);
        if((send(iClientSocket, cBuff, strlen(cBuff), 0)) < 0)
        {
            PRINTAPI_ERR("ReadInput API send erro\n");
            pthread_mutex_lock(&gQuitMutex);
            iQuitNum = 0;
            pthread_mutex_unlock(&gQuitMutex);
            continue;// iQuitNum = 0 jump loop
        }
        else if(0 == (send(iClientSocket, cBuff, strlen(cBuff), 0)))
        {
            PRINTAPI_ERR("Server disconnect\n");
            pthread_mutex_lock(&gQuitMutex);
            iQuitNum = 0;
            pthread_mutex_unlock(&gQuitMutex);
            continue;// iQuitNum = 0 jump loop
        }
    }

    if(iClientSocket != INITSOCKETE)
    {
        close(iClientSocket);
        iClientSocket = INITSOCKETE;
    }
    pthread_exit(NULL);
    PRINTAPI_TRC("Out ReadInput API\n");
    return NULL;
}

/*!
@brisf:read_input:receive_messages from server

*@para[in] void *pArg: NULL

*@return void*:
*/
void *RecvMess(void *pArg)
{
    PRINTAPI_TRC("Enter RecvMess API\n");
    s32 iClientSocket     = 0;
    u8 cBuff[BUFFER_SIZE] = {0};
    s32 iBytesRead        = 0;

    if(nullptr == pArg)
    {
        PRINTAPI_ERR("RecvMess API pArg is NullPointer\n");
        return NULL;
    }
    iClientSocket = *(s32 *)pArg;
    PRINTAPI_DBG("RecvMess API iClientSocket is %d\n", iClientSocket);

    PRINTAPI_DBG("RecvMess API iQuitNum is %d vsClientRun is %d \n", iQuitNum, vsClientRun);
    while(vsClientRun && iQuitNum)
    {
        iBytesRead = recv(iClientSocket, cBuff, BUFFER_SIZE - 1, 0);//Recv in loop
        PRINTAPI_DBG("RecvMess API iBytesRead is %d\n", iBytesRead);
        if(iBytesRead < 0)
        {
            PRINTAPI_ERR("RecvMess API recv erro\n");
            pthread_mutex_lock(&gQuitMutex);
            iQuitNum = 0;
            pthread_mutex_unlock(&gQuitMutex);
            continue;
        }
        else if(0 == iBytesRead)
        {
            PRINTAPI_ERR("Server Disconnect\n");
            pthread_mutex_lock(&gQuitMutex);
            iQuitNum = 0;
            pthread_mutex_unlock(&gQuitMutex);
            continue;
        }
        cBuff[iBytesRead] = '\0';
        PRINTAPI_MSG("\n");
        PRINTAPI_MSG("                       %s\n", cBuff);

        LogMess(cBuff);
    }

    if(iClientSocket != INITSOCKETE)
    {
        close(iClientSocket);
        iClientSocket = INITSOCKETE;
    }
    pthread_exit(NULL);
    PRINTAPI_TRC("Out RecvMess API\n");
    return NULL;
}

/*!
@brisf:main

*@return s32:
*\retval -6    If EN_FGETS_FAIL
*\retval -5    If EN_NULL_POINTER
*\retval -4    If EN_CREATSOC_FAIL.
*\retval -3    If ConnSocFai
*\retval -2    If EN_THREAD_JOINFAIL.
*\retval -1    If EN_THREAD_CREATFAIL
*\retval 0     If EN_SUCCESS.
*/
s32 main()
{
    PRINTAPI_TRC("Enter main API\n");

    //Init
    EN_ERRO_RETURN enRet = EN_SUCCESS;
    pthread_t tidInput   = 0;
    pthread_t tidRecv    = 0;

    //Register signal handler
    struct sigaction stSig = {};
    memset(&stSig, 0, sizeof(stSig));
    stSig.sa_handler = SigHandler;
    sigaction(SIGINT, &stSig, NULL);
    sigaction(SIGTERM, &stSig, NULL);

    //Set server address
    struct sockaddr_in stSockServAddr = {};
    memset(&stSockServAddr, 0, sizeof(stSockServAddr));// Use zero fill
    stSockServAddr.sin_family = AF_INET;//Use IPV4 address
    stSockServAddr.sin_port   = htons(MYPORT);
    inet_pton(AF_INET, IP, &stSockServAddr.sin_addr);

    //Input client name
    PRINTAPI_MSG("Enter your name: ");
    if((fgets(gcUserName, sizeof(gcUserName), stdin)) == NULL)
    {
        PRINTAPI_ERR("Fgets username fail\n");
        enRet = EN_FGETS_FAIL;
        PRINTAPI_DBG("enRet = %d\n", enRet);
        goto FREE_END;
    }
    gcUserName[strcspn(gcUserName, "\n")] = '\0';  //Remove newline character

    //Create client socket
    giClientSocket = socket(AF_INET, SOCK_STREAM, 0);
    if(giClientSocket < 0)
    {
        PRINTAPI_ERR("Creat socket fail\n");
        enRet = EN_CREATSOC_FAIL;
        PRINTAPI_DBG("enRet = %d\n", enRet);
        goto FREE_END;
    }

    //Connect to server
    if((connect(giClientSocket, (struct sockaddr *)&stSockServAddr, sizeof(stSockServAddr))) < 0)
    {
        PRINTAPI_ERR("Connect server fail\n");
        enRet = EN_CONNSOC_FAIL;
        PRINTAPI_DBG("enRet = %d\n", enRet);
        goto FREE_END;
    }
    PRINTAPI_MSG("Connected to server\n");

    //Creat recv pthread
    if((pthread_create(&tidRecv, NULL, RecvMess, &giClientSocket)) != 0)
    {
        PRINTAPI_ERR("Create pthread tidRecv fail\n");
        enRet = EN_THREAD_CREATFAIL;
        PRINTAPI_DBG("enRet = %d\n", enRet);
        goto THREAD_END;//If creat fail, then dont need join,goto end;
    }

    //Creat write pthread 
    if((pthread_create(&tidInput, NULL, ReadInput, &giClientSocket)) != 0)
    {
        PRINTAPI_ERR("Create pthread tidInput fail\n");
        enRet = EN_THREAD_CREATFAIL;
        PRINTAPI_DBG("enRet = %d\n", enRet);
        goto THREAD_END;
    }
THREAD_END:
    if((pthread_join(tidRecv, NULL)) != 0)
    {
        PRINTAPI_ERR("Thread tidRecv join fail\n");
        enRet = EN_THREAD_JOINFAIL;
        PRINTAPI_DBG("enRet = %d\n", enRet);
        goto THREAD2_END;
    }
THREAD2_END:
    if((pthread_join(tidInput, NULL)) != 0)
    {
        PRINTAPI_ERR("Thread tidInput join fail\n");
        enRet = EN_THREAD_JOINFAIL;
        PRINTAPI_DBG("enRet = %d\n", enRet);
        return enRet;
    }
FREE_END:
    if(giClientSocket != INITSOCKETE)
    {
        close(giClientSocket);
        giClientSocket = INITSOCKETE;
    }
    pthread_mutex_lock(&gLogMutex);
    if(nullptr != gpLogFile)
    {
        fclose(gpLogFile);
        gpLogFile = nullptr;
    }
    pthread_mutex_unlock(&gLogMutex);
    PRINTAPI_TRC("Out main API, enRet = %d\n", enRet);
    return enRet;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值