I've been trying to pass a variable to threads ,but the instant a second thread is created the value changes despite it being created as a constant variable.
//for the first user
if (flag == 0) {
//store the socket
cl_sc[0] = client_sock_desc;
//set id
whichOne[0] = 0;
puts("Client accepted");
//second user ,same procedure
}
else if (flag == 1) {
cl_sc[1] = client_sock_desc;
whichOne[0] = 1;
puts("Client accepted");
}
//create thread and pass cl_sc as arguement
pthread_t sTcThread;
pthread_create(&sTcThread, NULL, server_to_client, (void*)whichOne);
And here is the thread implimentation
void* server_to_client(void* socket_desc)
{
//make the arguement readable
const int* whichOne = (int*)socket_desc;
//one int for retrieved data and one for his socket
int retrieve, socket = cl_sc[whichOne[0]];
//chat buddy socket
int palsSocket;
//the actual data
char data[DATA_LENGTH];
//free the string
memset(data, 0, DATA_LENGTH);
for (;;) {
//set accordingly
if (whichOne[0] == 0) {
palsSocket = cl_sc[1];
}
else if (whichOne[0] == 1) {
palsSocket = cl_sc[0];
}
printf("Im %d to join my socket is %d and my pals socket is %d\n", whichOne[0], socket, palsSocket);
}
}
Results of the execution
Client accepted Im 0 to join my socket is 4 and my pals socket is 0
Client accepted Im 1 to join my socket is 5 and my pals socket is 4
But the moment thread 0 is activated this happens
Im 1 to join my socket is 4 and my pals socket is 4
Changing the whichOne constant to 1.
Solved as such thanks to the answers and comments .
int *whichOneImported = (int *) socket_desc;
int whichOne = whichOneImported[0];
const int *whichOne = (int *) socket_desc; guarantees that whichOne isn't changed by an instruction of your subroutine, but not by another thread, since it points on a shared memory area (you pass the address to the whichOne array when you create your thread, and you modify its value afterwards when flag == 1)
you set whichOne[0] = 1; in the other thread, and I'm not sure of the logic but maybe you meant:
whichOne[flag] = flag;
and then
pthread_create(&sTcThread, NULL, server_to_client, (void*) (whichOne+flag));
to separate the data
Or make a allocated copy of whichOne prior to running the thread.
Related
I am trying to fill a buffer using pthreads in a simple TCP/IP server client communication.
ATTENTION: Client writes its contents to an external server-address (not mine) and server reads its contents from an external client. The client and server that I have put below, do not communicate with each other.
The buffer is filled in two ways:
Server reads a message and puts it into the buffer
Client creates a message and puts it into the buffer
Here is the client function:
void *client(void *threadid)
{
//CLIENT INITIALIZATION AND CONNECT TO SERVER PROPERLY
//sleep(1); //sleep 1 second before you send again
char *buff = "message1"; //message1,2,3 etc is defined by a random function
pthread_mutex_lock(&lock);
write(sockfd, buff, strlen(buff)+1);
buffer_fill(buff);
pthread_mutex_unlock(&lock);
}
pthread_exit(NULL);
}
And here is the server function. Server reads from an external device that runs the same client code with me:
void *server(void *threadid)
{
//SERVER INITIALIZATION USING THE PROPER PORT AND ADDRESS
pthread_mutex_lock(&lock);
bzero(buff, MAX_LENGTH);
// read the message from client and copy it in buffer
while(strlen(buff) == 0){
read(sockfd, buff, sizeof(buff));
}
buffer_fill(buff);
pthread_mutex_unlock(&lock);
}
pthread_exit(NULL);
}
I am using a simple pthread initialization in my main function. So I am calling each function through the utilization of a thread:
int main(int argc, char **argv)
{
pthread_t threads[NUM_THREADS];
int rc[NUM_THREADS];
long t;
for(t=0; t<NUM_THREADS; t++){
//initiallize thread
if (pthread_mutex_init(&lock, NULL) != 0)
{
printf("\n mutex init failed\n");
return 1;
}
//create each thread according to value of t
if(t==0){
rc[t] = pthread_create(&threads[t], NULL, server, (void *)t);
}else if(t==1){
rc[t] = pthread_create(&threads[t], NULL, client, (void *)t);
}
}
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
pthread_mutex_destroy(&lock);
/* Last thing that main() should do */
pthread_exit(NULL);
return 0;
}
I assume the problem lies somewhere in the use of the (extremely simple) buffer_fill(char *message) in combination with the threads (note : msg is a global variable initialized to zero outside main, int msg = 0):
void buffer_fill(char *m){
if (msg<=MAX_MESSAGES){
buffer[msg] = m;
msg ++;
}
print_buffer();
}
When I execute this code continuously I get that kind of result:
first print:
message2
second print:
message1
message1
third print:
message5
message5
message5
and so on.
Note that messages[1:5] are been selected randomly by the client and do not affect the outcome
I assure you that the server client set up is correct. I checked it
before writing the code that fills the buffer
Why is it that messages print like that and not in a serial form? I want every random message that is going to be written by client and every message that is read by the server to be stacked on buffer one after the other like this:
first print:
message2
second print:
message2
message1
third print:
message2
message1
message5
you problem happens here
void buffer_fill(char *m){
if (msg<=MAX_MESSAGES){
buffer[msg] = m; // where
msg ++;
}
print_buffer();
}
you should copy the value to buffer from m using strcpy or using a loop.
Edit: char * <=> const char * you should create an array or dynamically allocate the buffer.
I am working on a client/server program that is supposed to take user input (two integers) and allow the user to calculate those to receive an answer.
When I run my program there seems to be an issue with either connecting to the client or opening the directory and I'm not sure what it could be. I'm entirely new to setting up servers and utilizing directories to read and write .txt files to.
Here are the parts of code that I think might be wrong and causing the issues I am facing, which is the program asks for a port number to connect to (2000 is what is recommended to use) so I enter that and then nothing happens.
// PURPOSE: To run the server by 'accept()'-ing client requests from
// 'listenFd' and doing them.
void doServer (int listenFd)
{
/* Application validity check: */
/* Server clients: */
pthread_t threadId;
pthread_attr_t threadAttr;
int threadCount = 0;
int *iPtr;
/* YOUR CODE HERE: */
while(1)
{
/* Accept connection to client: */
int connfd = accept(listenFd, NULL, NULL); //if I change this to getServerFileDescriptor (another function within the code, it will continuously loop through threadNumbers and do nothing as well).
/* Malloc memory for two integers: */
iPtr = (int *)calloc(2, sizeof(int));
/*Put file descriptor in the first space: */
iPtr[0] = listenFd; // or just listenFd not sure
/* put threadCount into the second space and increment: */
iPtr[1] = threadCount++;
/* Creates detached thread for handleClient and passes the address of iPtr */
pthread_attr_init(&threadAttr);
pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED);
pthread_create(&threadId, &threadAttr, handleClient, (void*)iPtr);
pthread_join(threadId, NULL);
pthread_attr_destroy(&threadAttr);
}
}
void* handleClient(void* vPtr)
{
/* Read command: */
char buffer[BUFFER_LEN];
char command;
int fileNum;
char text[BUFFER_LEN];
int shouldContinue = 1;
int threadNum;
int fd;
/* Cast void* vPtr back to an int */
int *iPtr = (int *)vPtr;
/* Assign file descriptor to a local value named 'fd'*/
fd = iPtr[0];
/* Assign thread number to local value named 'threadNum'*/
threadNum = iPtr[1];
free(iPtr);
while (shouldContinue)
{
memset(buffer,'\0',BUFFER_LEN);
memset(text ,'\0',BUFFER_LEN);
read(fd,buffer,BUFFER_LEN);
printf("Thread %d received: %s\n",threadNum,buffer);
sscanf(buffer,"%c %d \"%[^\"]\"",&command,&fileNum,text);
/* YOUR CODE HERE: */
if(command == DIR_CMD_CHAR)
{
/* 1. Open the current directory (named "."). If an error occurs then just send STD_ERROR_MSG back to the client: */
DIR* dirPtr = opendir(".");
struct dirent* entryPtr;
/* If error occurs send STD_ERROR_MSG to client: */
if ((dirPtr = opendir (".")) == NULL) {
{
write(fd, STD_ERROR_MSG, sizeof(STD_ERROR_MSG));
//return(EXIT_FAILURE);
}
/* Read as many entries that will fit into BUFFER_LEN
put as many entries into the buffer and send the buffer to client
d_name=entryPtr into the bufffer using strcat_s,
make sure buffer starts empty
buffer[0]='\n';
add new line char using stringcat "\n"
make sure do not go over buffer lengh */
if (dirPtr)
{
while ((entryPtr = readdir(dirPtr)) != NULL)
{
buffer[0]='\0';
int i;
int sizebuf = sizeof(buffer);
for (i = 0; i < sizebuf; i++)
{
strcat(buffer,entryPtr->d_name);
strcat(buffer,"\n");
}
}
}
/* 3. Close directory */
closedir(dirPtr);
}
Here's how the correct output should look.
$ ./mathClient Machine name [localhost.localdomain]? (I just pressed enter)
Port number? 2000
What would you like to do:
(1) List files
(2) Read a math file
(3) Write a math file
(4) Calculate a math file
(5) Delete a math file
(0) Quit
Your choice? 1
Sending "l"
0.bc
Here are the instructions for the code that I am having trouble with.
Implementing doServer(int listenFd) (10 Points):
doServer() should have a loop in which it waits for a client to connect to listenFd. When a client does, it should:
malloc() enough memory for 2 integers
put the file descriptor from accept() in one of those spaces
put the value of threadCount in the other space, and increment threadCount
Make a detached thread to handle this new client. I called my function handleClient(), but you may call yours whatever. Pass the address of your malloc()-ed array.
The loop should then go back for another accept().
void* handleClient(void* vPtr) (10 Points):
(Or whatever you call your function that runs a thread for the client.)
The thread id and the file descriptor are passed, but they come in as a void* pointer.
Use another pointer to cast back to int*
Save the file descriptor and thread number in local vars
free() the memory
Print the thread number and do a loop like this:
// II.B. Read command:
char buffer[BUFFER_LEN];
char command;
int fileNum;
char text[BUFFER_LEN];
int shouldContinue = 1;
while (shouldContinue)
{
text[0] = '\0';
read(fd,buffer,BUFFER_LEN);
printf("Thread %d received: %s\n",threadNum,buffer);
sscanf(buffer,"%c %d \"%[^\"]\"",&command,&fileNum,text);
// YOUR CODE HERE
}
It read()s a line of text from the client into buffer[], and parses the line into a command character, fileNum integer, and quote-delineated text[] string. (The fileNum and text[] may or may not be given, depending upon the value of command.)
Then do the following operations based upon the value of command. Except for QUIT_CMD_CHAR I strongly recommend using a different function for each!
When the function ends just have it do:
printf("Thread %d quitting.\n",threadNum);
return(NULL);
command == DIR_CMD_CHAR (15 Points):
Open the current directory (named "."). If an error occurs then just send STD_ERROR_MSG back to the client.
Copy as many entries that will fit into a buffer of length BUFFER_LEN. Be sure to put a separating '\n' after each entry.
Close the directory.
Any help would be appreciated, if you need the full code I could send that to you if that would help.
EDIT: Here are two additional functions, one called getPortNum() and another called getServerFileDescriptor() which address receiving a port number and setting up sockets for the connection. Additionally I included the main() which utilizes these.
// PURPOSE: To decide a port number, either from the command line arguments
// 'argc' and 'argv[]', or by asking the user. Returns port number.
int getPortNum (int argc,
char* argv[]
)
{
// I. Application validity check:
// II. Get listening socket:
int portNum;
if (argc >= 2)
portNum = strtol(argv[1],NULL,0);
else
{
char buffer[BUFFER_LEN];
printf("Port number to monopolize? ");
fgets(buffer,BUFFER_LEN,stdin);
portNum = strtol(buffer,NULL,0);
}
// III. Finished:
return(portNum);
}
// PURPOSE: To attempt to create and return a file-descriptor for listening
// to the OS telling this server when a client process has connect()-ed
// to 'port'. Returns that file-descriptor, or 'ERROR_FD' on failure.
int getServerFileDescriptor
(int port
)
{
// I. Application validity check:
// II. Attempt to get socket file descriptor and bind it to 'port':
// II.A. Create a socket
int socketDescriptor = socket(AF_INET, // AF_INET domain
SOCK_STREAM, // Reliable TCP
0);
if (socketDescriptor < 0)
{
perror(THIS_PROGRAM_NAME);
return(ERROR_FD);
}
// II.B. Attempt to bind 'socketDescriptor' to 'port':
// II.B.1. We'll fill in this datastruct
struct sockaddr_in socketInfo;
// II.B.2. Fill socketInfo with 0's
memset(&socketInfo,'\0',sizeof(socketInfo));
// II.B.3. Use TCP/IP:
socketInfo.sin_family = AF_INET;
// II.B.4. Tell port in network endian with htons()
socketInfo.sin_port = htons(port);
// II.B.5. Allow machine to connect to this service
socketInfo.sin_addr.s_addr = INADDR_ANY;
// II.B.6. Try to bind socket with port and other specifications
int status = bind(socketDescriptor, // from socket()
(struct sockaddr*)&socketInfo,
sizeof(socketInfo)
);
if (status < 0)
{
perror(THIS_PROGRAM_NAME);
return(ERROR_FD);
}
// II.B.6. Set OS queue length:
listen(socketDescriptor,5);
// III. Finished:
return(socketDescriptor);
}
int main (int argc,
char* argv[]
)
{
// I. Application validity check:
// II. Do server:
int port = getPortNum(argc,argv);
int listenFd = getServerFileDescriptor(port);
int status = EXIT_FAILURE;
if (listenFd >= 0)
{
doServer(listenFd);
close(listenFd);
status = EXIT_SUCCESS;
}
// III. Finished:
return(status);
I have a server application that creates new thread for every incoming request.
However, every once in a while, it will create a thread with thread ID = 0 (used pthread_equal to check this). I have a structure that contains the thread ID that I pass to the function specified in pthread_create, and am checking this there.
Why would a thread get created with ID = 0?
Is there anything I can do if this happens? I cannot use this thread and want to exit it immediately.
=====================================================================
typedef struct
{
pthread_t tid;
other_struct_t Other;
} data_ptr_t;
void * worker(void * arg)
{
data_ptr_t local_data;
data_ptr_t * incoming_data = (data_ptr_t *) arg;
if (NULL == incoming_data || NULL == incoming_data->Other)
{
printf("invalid input\n");
}
else if (pthread_equal(incoming_data->tid, 0))
{
printf("invalid thread id\n");
}
else
{
// add to global thread pool
// do other stuff here
// remove from global thread pool
}
}
int main()
{
// server socket stuff
while (1)
{
// if incoming connection is valid
data_ptr_t data;
int error = pthread_create(&(data.tid), NULL, (void * (*) (void *)) worker, (void *) &data);
if (0 != errror)
{
printf("could not create thread (%d)\n", error);
}
else
{
pthread_detach(data.tid);
printf("thread dispatched\n");
}
}
}
Note: If the number of threads I'm creating is under 50 or so, it works fine. Upwards of 70, most threads go through just fine, the rest end up printing the "invalid thread id".
Note: This is on Linux.
You can't do this:
while (1)
{
// if incoming connection is valid
data_ptr_t data;
int error = pthread_create(&(data.tid),
NULL, (void * (*) (void *)) worker, (void *) &data);
your data_ptr_t is a local variable on the stack. On the next iteration of the while loop, that variable is destroyed/gone/not-valid.
The while loop might start another iteration long before the new worker thread starts running and makes use of the data you pass to it. Instead, dynamically allocate the data you pass to the worker thread so you can be sure it's still valid.
The Situation
After reading Unix Socket Programming, W.Richard Steven, I'm writing a P2P program in which the main thread creates thread pool in which five sub-threads live. it then monitors 50 sockets with kqueue(). when a event occurs in a specified socket (e.g, receiving data on the socket.), the main thread copies socket descriptor into a shared array and awakes one thread in the thread pool. the sub thread then processes a request from the socket. Also, I have protected the shared array using both mutex variable and conditional variable.
Question
The Author presents the source codes "server/serv08.c" and "server/pthread08.c" in the Section 30.12 and 30.13 in the book, respectively, as if there is no something wrong with this code. But, when I've written a code snippet similar to one author present, thread synchronization doesn't work well. Why does iput become equal to iget in main thread?
Code
--Global variable--
typedef struct tagThread_information
{
int sockfd;
} Thread_information;
Thread_information peer_fds[MAX_THREAD];
pthread_mutex_t peerfd_mutex;
pthread_cond_t peerfd_cond;
pthread_mutex_t STDOUT_mutex;
int iput;
int iget;
--Main thread--
void Wait_for_Handshake(download_session *pSession, int nMaxPeers)
{
struct kevent ev[50], result[50];
int kq, i, nfd;
int c = 1;
if( (kq = kqueue()) == -1)
{
fprintf(stderr, "fail to initialize kqueue.\n");
exit(0);
}
for(i = 0 ; i < nMaxPeers; i++)
{
EV_SET(&ev[i], pSession->Peers[i].sockfd, EVFILT_READ, EV_ADD, 0, 0, 0);
printf("socket : %d\n", (int)ev[i].ident);
}
// create thread pool. initialize mutex and conditional variable.
iput = 0;
iget = 0;
pthread_mutex_init(&STDOUT_mutex, NULL);
pthread_mutex_init(&peerfd_mutex, NULL);
pthread_cond_init(&peerfd_cond, NULL);
// Assume that MAX_THREAD is set to 5.
for(i = 0 ; i < MAX_THREAD; i++)
thread_make(i);
while(1)
{
nfd = kevent(kq, ev, nMaxPeers, result, nMaxPeers, NULL);
if(nfd == -1)
{
fprintf(stderr, "fail to monitor kqueue. error : %d\n", errno);
nMaxPeers = Update_peer(ev, pSession->nPeers);
pSession->nPeers = nMaxPeers;
continue;
}
for(i = 0 ; i < nfd; i++)
{
pthread_mutex_lock(&peerfd_mutex);
peer_fds[iput].sockfd = (int)result[i].ident;
if( ++iput == MAX_THREAD)
iput = 0;
if(iput == iget) // Here is my question.
{
exit(0);
}
pthread_cond_signal(&peerfd_cond);
pthread_mutex_unlock(&peerfd_mutex);
}
}
}
--sub thread--
void * thread_main(void *arg)
{
int connfd, nbytes;
char buf[2048];
for( ; ; )
{
/* get socket descriptor */
pthread_mutex_lock(&peerfd_mutex);
while( iget == iput)
pthread_cond_wait(&peerfd_cond, &peerfd_mutex);
connfd = peer_fds[iget].sockfd;
if ( ++iget == MAX_THREAD )
iget = 0;
pthread_mutex_unlock(&peerfd_mutex);
/* process a request on socket descriptor. */
nbytes = (int)read(connfd, buf, 2048);
if(nbytes == 0)
{
pthread_mutex_lock(&STDOUT_mutex);
printf("\n\nthread %ld, socket : %d, nbytes : %d\n\n\n", (long int)pthread_self(), connfd, nbytes);
printf("socket closed\n\n");
pthread_mutex_unlock(&STDOUT_mutex);
close(connfd);
continue;
}
else if(nbytes == -1)
{
close(connfd);
pthread_mutex_lock(&STDOUT_mutex);
printf("\n\nthread %ld, socket : %d, nbytes : %d\n\n\n", (long int)pthread_self(), connfd, nbytes);
perror("socket error : ");
write(STDOUT_FILENO, buf, nbytes);
printf("\n\n\n\n");
pthread_mutex_unlock(&STDOUT_mutex);
continue;
}
pthread_mutex_lock(&STDOUT_mutex);
printf("\n\nthread %ld, socket : %d, nbytes : %d\n\n\n", (long int)pthread_self(), connfd, nbytes);
write(STDOUT_FILENO, buf, nbytes);
printf("\n\n\n\n");
pthread_mutex_unlock(&STDOUT_mutex);
}
}
In your main thread:
if( ++iput == MAX_THREAD)
iput = 0;// so iput is 0 --> MAX_THREAD
And in your sub thread:
if ( ++iget == MAX_THREAD )
iget = 0;// So iget is 0 --> MAX_THREAD
Since the sub thread and the main thread runs at the "same time",and they are golbal values .the iput maybe equare to iget sometime.
From "UNIX Network Prgramming Volume 1, 2nd Edition", chapter 27.12, page 757, from the annotations to the lines 27-38 of server/serv08.c:
We also check that the iput index has not caught up with the iget index, which indicates that our array is not big enough.
For reference the lines mentioned above (take from here):
27 for ( ; ; ) {
28 clilen = addrlen;
29 connfd = Accept(listenfd, cliaddr, &clilen);
30 Pthread_mutex_lock(&clifd_mutex);
31 clifd[iput] = connfd;
32 if (++iput == MAXNCLI)
33 iput = 0;
34 if (iput == iget)
35 err_quit("iput = iget = %d", iput);
36 Pthread_cond_signal(&clifd_cond);
37 Pthread_mutex_unlock(&clifd_mutex);
38 }
What you have there is a typical circular buffer implementation.
The head and tail pointers/indices point to the same location when the circular buffer is empty. You can see this being tested in the code while (iget == iput) ... which means "while the queue is empty ...".
If, after an insertion at the head of a circular buffer, head points to tail, that is a problem. The buffer has overflowed. It is a problem because now the buffer now looks empty even though it is full.
That is to say, one unused location is reserved in the buffer; if the buffer has 4096 entries, we can only fill 4095. If we fill 4096, it then we have overflow: it looks like an empty circular buffer.
(We could use all 4096 locations if we allowed the index to go from 0 to 8192, using an extra bit to resolve the ambiguity, so that instead of wrapping to zero past 4095, the pointers would keep going to 4096 ... 8191. We would have to remember to access the array modulo 4096, of course. It's a big cost in complexity for the sake of recovering one wasted element.)
It looks like the code bails on circular buffer overflow because it is structured such that this condition cannot happen, and so it constitutes an internal error. The circular buffer overflows when there are too many descriptors being passed from the producer to the consumer in a single bout.
In general, circular buffer code cannot just bail when the buffer is full. Either the insertion operation has to balk and return an error, or it has to block for more space. So this is a special case based on assumptions particular to the example program.
Objective: N nodes (running on different machines) should communicate with each other by establishing TCP connections with each other. Sending and receiving messages are done by 2 threads created by the process. Initially the main process connects all nodes with each other, creates the 2 threads and gives it a list of file descriptors which can be used by threads to send and receive data. The below structure is filled by the main process and passed to the threads.
typedef struct
{
char hostName[MAXIMUM_CHARACTERS_IN_HOSTNAME]; /* Host name of the node */
char portNumber[MAXIMUM_PORT_LENGTH]; /* Port number of the node */
char nodeId[MAXIMUM_NODE_ID_LENGTH]; /* Node ID of the node */
int socketFd; /* Socket file descriptor */
int socketReady; /* Flag to indicate if socket information is filled */
}SNodeInformation;
PS: socketFd is the socket descriptor received by either accept() or by socket() depending on how the connection was established (Either listening to connections from a node or connecting to a node).
An array of SNodeInformation of size MAX_NUM_OF_NODES is used.
The send thread goes through the nodeInformation and sends a message "Hello" to all nodes as except itself show below.
void *sendMessageThread(void *pNodeInformation) {
int i;
int ownNodeId;
int bytesSent = 0;
char ownHostName[MAXIMUM_CHARACTERS_IN_HOSTNAME];
SNodeInformation *nodeInformation = (SNodeInformation *) pNodeInformation;
SNodeInformation *iterNodeInformation;
printf("SendMessageThread: Send thread created\n");
if(gethostname(ownHostName, MAXIMUM_CHARACTERS_IN_HOSTNAME) != 0) {
perror("Error: sendMessageThread, gethostname failed\n");
exit(1);
}
for(i=0, iterNodeInformation=nodeInformation ; i<MAXIMUM_NUMBER_OF_NODES ; i++, iterNodeInformation++) {
if(strcmp((const char*) iterNodeInformation->hostName, (const char*) ownHostName) != 0) {
/* Send message to all nodes except yourself */
bytesSent = send(iterNodeInformation->socketFd, "Hello", 6, 0);
if(bytesSent == -1) {
printf("Error: sendMessageThread, sending failed, code: %s FD %d\n", strerror(errno), iterNodeInformation->socketFd);
}
}
}
pthread_exit(NULL);
}
The receive thread goes through the nodeInformation, sets up a file descriptor set and uses select to wait for incoming data as show below.
void *receiveMessageThread(void *pNodeInformation)
{
int i;
int fileDescriptorMax = -1;
int doneReceiving = 0;
int numberOfBytesReceived = 0;
int receiveCount = 0;
fd_set readFileDescriptorList;
char inMessage[6];
SNodeInformation *nodeInformation = (SNodeInformation *) pNodeInformation;
SNodeInformation *iterNodeInformation;
printf("ReceiveMessageThread: Receive thread created\n");
/* Initialize the read file descriptor */
FD_ZERO(&readFileDescriptorList);
for(i=0, iterNodeInformation=nodeInformation ; i<MAXIMUM_NUMBER_OF_NODES ; i++, iterNodeInformation++) {
FD_SET(iterNodeInformation->socketFd, &readFileDescriptorList);
if(iterNodeInformation->socketFd > fileDescriptorMax) {
fileDescriptorMax = iterNodeInformation->socketFd;
}
}
printf("ReceiveMessageThread: fileDescriptorMax:%d\n", fileDescriptorMax);
while(!doneReceiving) {
if (select(fileDescriptorMax+1, &readFileDescriptorList, NULL, NULL, NULL) == -1) {
perror("Error receiveMessageThread, select failed \n");
return -1;
}
for(i=0 ; i<fileDescriptorMax ; i++) {
if (FD_ISSET(i, &readFileDescriptorList)) {
/* Check if any FD was set */
printf("ReceiveThread: FD set %d\n", i);
/* Receive data from one of the nodes */
if ((numberOfBytesReceived = recv(i, &inMessage, 6, 0)) <= 0) {
/* Got error or connection closed by client */
if (numberOfBytesReceived == 0) {
/* Connection closed */
printf("Info: receiveMessageThread, node %d hung up\n", i);
}
else {
perror("Error: receiveMessageThread, recv FAILED\n");
}
close(i);
/* Remove from Master file descriptor set */
FD_CLR(i, &readFileDescriptorList);
doneReceiving = 1;
}
else {
/* Valid data from a node */
inMessage[6] = '\0';
if(++receiveCount == MAXIMUM_NUMBER_OF_NODES-1) {
doneReceiving = 1;
}
printf("ReceiveThread: %s received, count: %d\n", inMessage, rece iveCount);
}
}
}
}
pthread_exit(NULL);
}
Expected Output: I tried with just 2 processes, P1 (Started first) and P2 running on machine1 and another on machine2. Both the processes in the machines should first connect and then the threads should send and receive the message "Hello" and exit.
Observed Output: The P1 is able to send the message and P2 (receiver thread) is able to receive the message "Hello". But P1 (receiver thread) is not able to get the message from P2 (Sending thread). Application code is the same in both the machines but every time, the process started first does not get the message from the other process. I added a print to just check if some file descriptor was set, but I don't see it for P1 but only for the P2. The send in the receiving process is not failing, it returns with 6. I checked the maximum value of file descriptors, its correct.
If I start P2 first and then P1 then I can see that P1 receives the message from P2 and exists while P2 waits infinitely for the message from P1.
I am not sure if the problem is because of incorrect use of socket descriptors or because of threads ?
Two issues:
1 The loop testing for a file descriptor being set, does not include all file descriptors put into the set. (This programming error is expected to be the reason for the malfunction described in the OP.)
2 The sets of file descriptors passed to select() are modified by select(), so the set need to be re-initialized before for select() again. (The programming error would only be notable if from more than one socket data sall be received.)
Please see the following mod/s to the OP's code:
void *receiveMessageThread(void *pNodeInformation)
{
...
printf("ReceiveMessageThread: Receive thread created\n");
while(!doneReceiving) {
/* Initialize the read-set of file descriptors */
/* Issue 2 fixed from here ... */
FD_ZERO(&readFileDescriptorList);
for(i=0, iterNodeInformation=nodeInformation ; i<MAXIMUM_NUMBER_OF_NODES ; i++, iterNodeInformation++) {
FD_SET(iterNodeInformation->socketFd, &readFileDescriptorList);
if (iterNodeInformation->socketFd > fileDescriptorMax) {
fileDescriptorMax = iterNodeInformation->socketFd;
}
}
/* ... up to here. */
printf("ReceiveMessageThread: fileDescriptorMax:%d\n", fileDescriptorMax);
if (select(fileDescriptorMax+1, &readFileDescriptorList, NULL, NULL, NULL) == -1) {
perror("Error receiveMessageThread, select failed \n");
return -1;
}
for(i=0 ; i <= fileDescriptorMax ; i++) { /* Issue 1 fixed here. */
...