I have this program that is prototype for a game of connectfour, as a homework project. So far so good, but I have major question, how do I limit the clients to only 2 of them, and also, how can I easily identify them when I am going to verify which column pick comes from which one?
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
//used port
#define PORT 6660
//array limits
#define WIDTH 7
#define HEIGTH 6
//error code for some applications
extern int errno;
//static column variables
static int gameVariables [WIDTH] = {6, 6, 6, 6, 6, 6, 6};
static char gameArray[HEIGTH][WIDTH];
static void *treat(void *);//function called by every thread
typedef struct thData
{
pthread_t idThread; //id Thread
int cl;//descriptor returned by accept
}thData;
//Thread *threadsPool; //Threads array
//int sd;//listenning socket descriptor
//int nthreads; //number of threadsPool
//pthread_mutex_t mlock = PTHREAD_MUTEX_INITIALIZER; //mutex variable
static void *treat(void *);
//void raspunde (void *);
void connectFour(void *);
void printArray( char array[HEIGTH][WIDTH])
{
int k, j;
for( k = 0; k < HEIGTH; k++ )
{
for( j=0; j < WIDTH; j++ )
printf("%c ", array[k][j]);
printf("\n");
}
}
int main( )
{
//game array inialization
int k, j;
for( k = 0; k < HEIGTH; k++ )
for( j = 0; j < WIDTH; j++ )
gameArray[k][j] = (char) 79;
printArray(gameArray);
struct sockaddr_in server; //structure used by server
//void threadCreate(int);
struct sockaddr_in from;
int message;
int sd;
int pid;
pthread_t th[100];
int i = 0;
/*if(argc < 2)
{
fprintf(stderr, "Error: first argument is the number of thread\n");
exit(1);
}
nthreads = atoi(argv[1]);
if(nthreads <= 0)
{
fprintf(stderr,"Error: number of threads invalid\n");
exit(1);
}
threadsPool = calloc(sizeof(Thread), nthreads);
*/
//create socket
if((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("[SERVER] Error at socket\n");
return errno;
}
//using SO_REUSEADDR
int on = 1;
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
//preparing data structures
bzero(&server, sizeof(server));
bzero(&from, sizeof(from));
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(PORT);
//bind the socket
if(bind(sd, (struct sockaddr *) &server, sizeof(struct sockaddr) )== -1)
{
perror("[SERVER] Error at bind\n");
return errno;
}
//server listening
if(listen(sd, 2) == -1)
{
perror("[SERVER] Error at listen\n");
return errno;
}
/* printf("Number of threads %d\n", nthreads);
fflush(stdout);
int i;
for(i = 0; i < nthreads; i++)
threadCreate(i);
//serving concurrent clients using threads
for( ; ; )
{
printf("[SERVER] Listening at port : %d", PORT);
pause();
}//for
*/
//serving clients
for( ; ; )
{
int client;
thData *td; //parameter executed by thread
int length = sizeof(from);
printf("[SERVER] Waiting at port : %d\n", PORT);
fflush(stdout);
//accept client
if((client = accept (sd, (struct sockaddr *) &from, &length)) < 0)
{
perror ("[SERVER]Error at accept\n");
continue;
}
//connection established
int idThread; //thread id
int cl;
td = (struct thData*)malloc(sizeof(struct thData));
td -> idThread = i++;
td -> cl = client;
pthread_create (&th[i], NULL, &treat, td);
} //for
};//main
static void *treat(void * arg)
{
struct thData tdL;
tdL= *((struct thData*)arg);
printf ("[thread]- %d - Waiting message\n", tdL.idThread);
fflush (stdout);
pthread_detach(pthread_self());
connectFour((struct thData*)arg);
/* am terminat cu acest client, inchidem conexiunea */
close ((int)arg);
return(NULL);
};
/*
void raspunde (void *arg)
{
int i = 0;
char message[50], message2[100];
struct thData tdL;
tdL = *((struct thData*) arg);
bzero(message, 50);
if(read(tdL.cl, message, 50) <= 0)
{
printf("[thread %d]\n", tdL.idThread);
perror("Error at read from client\n");
}
printf("[thread %d] Message was received %s\n", tdL.idThread, message);
//preparing answer
/*bzero(message2, 100);
strcat(message2, "Hello, ");
strcat(message2, message);
printf("[thread %d] Sending back message %s\n", tdL.idThread, message2);
//returning message
if(write(tdL.cl, message2, 100) <= 0)
{
printf("[thread %d]\n", tdL.idThread);
perror("[thread] Error at write\n");
}
else
printf("[thread %d] Message was sent with success\n", tdL.idThread);
};
*/
void connectFour( void *arg)
{
int playerPick;
char message[50];
struct thData tdL;
tdL = *((struct thData*) arg);
bzero(message, 2);
if(read (tdL.cl, message, 50) <= 0)
{
printf("[thread %d]\n", tdL.idThread );
perror("Error at read from client\n");
}
printf ("[thread %d]Column pick received is : %s\n", tdL.idThread, message);
playerPick = atoi(message);
printf("playerPick is : %d\n", playerPick);
fflush(stdout);
switch(playerPick)
{
case 1:
if(gameVariables[0] >0 && gameVariables[0] < 7)
{
--gameVariables[0];
gameArray[gameVariables[0]][0] = (char) 82;
}
printArray(gameArray);
break;
case 2:
if(gameVariables[1] >0 && gameVariables[1] < 7)
{
--gameVariables[1];
gameArray[gameVariables[1]][1] = (char) 82;
}
printArray(gameArray);
break;
case 3:
if(gameVariables[2] >0 && gameVariables[2] < 7)
{
--gameVariables[2];
gameArray[gameVariables[2]][2] = (char) 82;
}
printArray(gameArray);
break;
case 4:
if(gameVariables[3] >0 && gameVariables[3] < 7)
{
--gameVariables[3];
gameArray[gameVariables[3]][3] = (char) 82;
}
printArray(gameArray);
break;
case 5:
if(gameVariables[4] >0 && gameVariables[4] < 7)
{
--gameVariables[4];
gameArray[gameVariables[4]][4] = (char) 82;
}
printArray(gameArray);
break;
case 6:
if(gameVariables[5] >0 && gameVariables[5] < 7)
{
--gameVariables[5];
gameArray[gameVariables[5]][5] = (char) 82;
}
printArray(gameArray);
break;
case 7:
if(gameVariables[6] >0 && gameVariables[6] < 7)
{
--gameVariables[6];
gameArray[gameVariables[6]][6] = (char) 82;
}
printArray(gameArray);
break;
}
printf("%d %d %d %d %d %d %d\n", gameVariables[0], gameVariables[1], gameVariables[2], gameVariables[3], gameVariables[4], gameVariables[5], gameVariables[6]);
}
;
You simply keep a counter that you check when accepting connections. When a client connect you check the counter and if it's beyond the limit then close the connection, else you keep the connection and increase the counter. When a client disconnects (for whatever reason) you decrease the counter.
It's important that you actually accept all connection, even if you just close them again immediately. This is because the queue of sockets waiting for accept
is not limitless. Once you fill it up no more clients will be able to connect.