I have main server code, which uses select and waits for hosts activities. I have also global structure, which stores all clients and theirs sockets.
//old code
Select in main thread unblocks intself when one of the hosts from clients array disconnects. Then I try to read data, and when it is 0, client is disconnected. Why select in Thread doesn't work in the same way? It works perfect when clients exchange data, but there is no reaction, when one of clients disconnects.
EDIT.
Sorry I have previously posted the code, which could not be compiled. The idea was, just to get the information if my idea of clients handling is correct and if this idea should work. I have created simple example and now it works. So, I have to review my oryginal code.
Working example:
#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string.h>
#include <arpa/inet.h>
#include <fcntl.h> // for open
#include <unistd.h> // for close
#include <pthread.h>
#include <limits.h>
#include <errno.h>
#include <time.h>
#include <sys/wait.h>
#define MAXCLIENTS 1000
#define FRAMESIZE 40
struct Client
{
int socket;
char state;
};
struct Client clients[2];
struct ThreadArgs
{
int srcClientIdx;
int dstClientIdx;
};
int portNumber=8090;
void * SocketThread(void *args)
{
printf("New thread created.\n");
struct ThreadArgs *threadArgs = (struct ThreadArgs*)args;
int sidx = threadArgs->srcClientIdx;
int didx = threadArgs->dstClientIdx;
int srcSocket = clients[sidx].socket;
int dstSocket = clients[didx].socket;
fd_set readfds;
struct timeval timeout;
while(1)
{
FD_ZERO(&readfds);
FD_SET(srcSocket, &readfds);
FD_SET(dstSocket, &readfds);
printf("Waiting for activities in thread.\n");
timeout.tv_sec = 60;
timeout.tv_usec = 0;
int activity = select(MAXCLIENTS+1, &readfds , NULL , NULL , &timeout);
if ((activity < 0) && (errno!=EINTR))
printf("Activity error.\n");
else if(activity == 0)
printf("Activity timeout.\n");
if (FD_ISSET(srcSocket, &readfds))
{
unsigned char buffer[FRAMESIZE];
int bytesCnt = read(srcSocket, buffer, sizeof(buffer));
if(bytesCnt == 0)
{
printf("Client%d disconnected.\n",sidx);
clients[sidx].state = 0;
clients[sidx].socket = -1;
pthread_exit(NULL);
}
else
printf("Client%d activity.\n",sidx);
}
if (FD_ISSET(dstSocket, &readfds))
{
unsigned char buffer[FRAMESIZE];
int bytesCnt = read(dstSocket, buffer, sizeof(buffer));
if(bytesCnt == 0)
{
printf("Client%d disconnected.\n",didx);
clients[didx].state = 0;
close(clients[didx].socket);
clients[didx].socket = -1;
pthread_exit(NULL);
}
else
printf("Client%d activity.\n",didx);
}
}
}
int ConfigureTCPIPconnection(int socket,struct sockaddr_in *serverAddr)
{
// Address family = Internet
serverAddr->sin_family = AF_INET;
//Set port number, using htons function to use proper byte order
serverAddr->sin_port = htons(portNumber);
//Incoming addresses
serverAddr->sin_addr.s_addr = INADDR_ANY;
//Set all bits of the padding field to 0
memset(serverAddr->sin_zero, '\0', sizeof serverAddr->sin_zero);
//Bind the address struct to the socket
if(bind(socket, (struct sockaddr *)serverAddr, sizeof(struct sockaddr)) < 0)
{
printf("Binding failed. %s\n",strerror(errno));
return 1;
}
printf("Bind sucessfull.\n");
return 0;
}
int CheckSocketActivity(fd_set *readfds)
{
int activity = select( MAXCLIENTS + 1 , readfds , NULL , NULL , NULL);
if ((activity < 0) && (errno!=EINTR))
return 1;
return 0;
}
int main(int argc, char *argv[])
{
fd_set readfds;
int serverSocket,newSocket;
pthread_t td; //thread descriptor
struct sockaddr_in serverAddr, newAddr={0};
socklen_t addr_size;
clients[0].state = 0;
clients[0].socket = -1;
clients[1].state = 0;
clients[1].socket = -1;
if((serverSocket = socket(PF_INET, SOCK_STREAM, 0)) == 0)
{
printf("Server socket creation failed.\n");
exit(1);
}
if(ConfigureTCPIPconnection(serverSocket,&serverAddr))
{
printf("Binding failed.\n");
exit(2);
}
if(listen(serverSocket,MAXCLIENTS))
{
printf("Listen error.\n");
exit(3);
}
printf("Listening...\n");
while(1)
{
FD_ZERO(&readfds); //clear fd set
FD_SET(serverSocket, &readfds); //add server socket to fd set
if(clients[0].state == 1)
FD_SET(clients[0].socket, &readfds); //add active clients to fd set
if(clients[1].state == 1)
FD_SET(clients[1].socket, &readfds);
printf("Waiting for activities.\n");
if(!CheckSocketActivity(&readfds))
{
if(FD_ISSET(serverSocket, &readfds))
{
if((newSocket = accept(serverSocket, (struct sockaddr *)&newAddr, (socklen_t*)&addr_size))<0) //create new socket
printf("New socket error. %s\n",strerror(errno));
else
{
printf("New socket connected.\n");
if(clients[0].state == 0)
{
printf("Client0 added.\n");
clients[0].state = 1;
clients[0].socket = newSocket;
}
else if(clients[1].state == 0)
{
printf("Client1 added.\n");
clients[1].state = 1;
clients[1].socket = newSocket;
}
}
}
else
{
for(int i=0;i<2;i++)
{
int srcSock = clients[i].socket;
if (FD_ISSET(srcSock, &readfds))
{
unsigned char buffer[FRAMESIZE];
int bytesCnt = read(srcSock, buffer, sizeof(buffer));
if(bytesCnt == 0)
{
printf("Client%d disconnected.\n",i);
clients[i].state = 0;
close(clients[i].socket);
clients[i].socket = -1;
}
else
{
if(clients[0].state == 1 && clients[1].state == 1)
{
int srcIndex,dstIndex;
//some other stuff
clients[0].state = 2;
clients[1].state = 2;
if(i == 0)
{
srcIndex = 0;
dstIndex = 1;
}
else
{
srcIndex = 1;
dstIndex = 0;
}
printf("Creating new thread.\n");
struct ThreadArgs threadArgs = {srcIndex,dstIndex};
if(pthread_create(&td, NULL, SocketThread, &threadArgs) != 0)
printf("Failed to create thread.\n");
if (pthread_detach(td))
printf("Thread detach error.\n");
}
else
printf("Two clients required for creating thread.\n");
}
}
}
}
}
}
}