/*********************************************************************************
Copyright (cpp) Novatek Microelectronics Corp., Ltd. All Rights Reserved.
\file client.cpp
\brief achieve two terninal communication
\for Liunx
\chip none
\Date 2024-08-13
\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 <sys/time.h>
#include <signal.h>
#include <sys/select.h>
#include "PrintLevel.h"
#define BUFFER_SIZE (1024)
#define MAX_CLIENTS (2)
#define MYPORT (1111)
#define IP ("127.0.0.1")
typedef unsigned int u32;
typedef unsigned short u16;
typedef char u8;
typedef int s32;
enum EN_ERRO_RETURN
{
ArgcFault = -3,
BindFail = -2,
ListenSocFail = -1,
Success = 0
};
static s32 giServerSocket = -1;
static s32 giClientSockets[MAX_CLIENTS] = {0};
static s32 giClientCount = 0;
static pthread_mutex_t gClientMutex = PTHREAD_MUTEX_INITIALIZER;
s32 g_PRINTAPI_level = g_PRINTAPI_msg;
volatile sig_atomic_t vsServerRunSig = 1;
/*!
@brisf:handle_signal
*@para[in] const u8 *message
*@return void:
*/
void handle_signal(s32 iSig)
{
PRINTAPI_trc("Enter handle_signal API\n");
if (iSig == SIGINT)
{
printf("\nServer interrupted by user (Ctrl+C). Exiting...\n");
if(giServerSocket != -1)
{
close(giServerSocket);
giServerSocket = -1;
}
exit(EXIT_SUCCESS);
}
else if (iSig == SIGTSTP)
{
printf("\nServer suspended by user (Ctrl+Z). Resuming...\n");
if(giServerSocket != -1)
{
close(giServerSocket);
giServerSocket = -1;
}
exit(EXIT_SUCCESS);
}
PRINTAPI_trc("out handle_signal API\n");
}
/*!
@brisf:handle_clien
*@para[in] void *pArg
*@return void*:
*/
void *HandleClient(void *pArg)
{
PRINTAPI_trc("Enter handle_client API\n");
if(nullptr == pArg)
{
PRINTAPI_err("nullpointer\n");
return NULL;
}
u8 cBuff[BUFFER_SIZE] = {0};
s32 iBytesRead = 0;
s32 iClientSocket = *(s32 *)pArg;
PRINTAPI_dbg("iClientSocket is %d \n", iClientSocket);
while (vsServerRunSig)
{
iBytesRead = recv(iClientSocket, cBuff, BUFFER_SIZE - 1, 0);
if (iBytesRead <= 0) //=0 close connenct
{
PRINTAPI_err("recv");
//vsServerRunSig = 0;
break;
}
cBuff[iBytesRead] = '\0';
PRINTAPI_msg("%s\n", cBuff);
// brocast news to other clients
pthread_mutex_lock(&gClientMutex);
for (s32 i = 0; i < giClientCount; i++)
{
if (giClientSockets[i] != iClientSocket)
{
if (send(giClientSockets[i], cBuff, strlen(cBuff), 0) < 0)
{
PRINTAPI_err("senderro");
}
}
}
pthread_mutex_unlock(&gClientMutex);
}
if (iBytesRead < 0)
{
PRINTAPI_err("recv");
}
else if (0 == iBytesRead)
{
PRINTAPI_err("Client %d disconnected\n",iClientSocket);
}
// remove client from clientlist
pthread_mutex_lock(&gClientMutex);
for (s32 i = 0; i < giClientCount; i++)
{
if (giClientSockets[i] == iClientSocket)
{
for (s32 j = i; j < giClientCount - 1; j++)
{
giClientSockets[j] = giClientSockets[j + 1];
}
giClientCount--;
pthread_mutex_unlock(&gClientMutex);
break;
}
}
pthread_mutex_unlock(&gClientMutex);
close(iClientSocket);
PRINTAPI_trc("out handle_client API\n");
return NULL;
}
/*!
@brisf:main
*@para[in]
*@return s32:
*\retval -2 If BindFail
*\retval -1 If ListenSocFail
*\retval 0 If success.
*/
s32 main()
{
PRINTAPI_trc("Enter main API\n");
// create server socket
giServerSocket = socket(AF_INET, SOCK_STREAM, 0);
s32 iClientSocket = -1;
pthread_t tidClient = {};
// set server address
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;// use IPV4 address
server_addr.sin_addr.s_addr = inet_addr(IP);// ip
server_addr.sin_port = htons(MYPORT); // port
// Register signal handler
struct sigaction sa;
sa.sa_handler = handle_signal;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTSTP, &sa, NULL);
// bind socket to addr
if (bind(giServerSocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
{
PRINTAPI_err("bindSocFail");
close(giServerSocket);
PRINTAPI_trc("out main API\n");
return BindFail;
}
// listen connect request
if (listen(giServerSocket, MAX_CLIENTS) < 0)
{
PRINTAPI_err("ListenSocFail");
close(giServerSocket);
PRINTAPI_trc("out main API\n");
return ListenSocFail;
}
PRINTAPI_msg("Server listening on port %d\n", MYPORT);
while (vsServerRunSig)
{
// recieive client connect request
iClientSocket = accept(giServerSocket, NULL, NULL);
if (iClientSocket < 0)
{
PRINTAPI_err("accept");
goto END;//enter next loop
}
// add new client to list
pthread_mutex_lock(&gClientMutex);
if (giClientCount < MAX_CLIENTS)
{
giClientSockets[giClientCount++] = iClientSocket;
PRINTAPI_msg("New client :% d connected\n", iClientSocket);
}
else
{
PRINTAPI_msg("Maximum number of clients reached\n");
pthread_mutex_unlock(&gClientMutex);
goto END;
}
pthread_mutex_unlock(&gClientMutex);
// creat pthread of client connect
if (pthread_create(&tidClient, NULL, HandleClient, &iClientSocket) != 0)
{
PRINTAPI_err("pthread_create");
goto END;
}
pthread_detach(tidClient);
END:
if(iClientSocket != -1)
{
close(iClientSocket);
iClientSocket = -1;
}
continue;
}
if(giServerSocket != -1)
{
close(giServerSocket);
giServerSocket = -1;
}
PRINTAPI_trc("out main API\n");
return Success;
}