I am trying to send and receive in different threads. When I use the code below I get a bad address error, I guess because my server address could not be properly passed to the thread function.
Code:
#include "client.h"
struct global_table{
struct sockaddr_in *serveraddr;
int sockID;
};
void *recvFromServer(struct global_table *rec){
char recBuf[RECVBUFSIZE];
int serverSize = sizeof(rec->serveraddr);
while(1)
{
int n = recvfrom(rec->sockID, recBuf, RECVBUFSIZE, 0, &rec->serveraddr, &serverSize);
if (n < 0)
perror("ERROR in recvfrom");
decryptData(recBuf);
printf("Recieved: %s\n", recBuf);
pthread_exit(NULL);
}
}
void pingServer(char *hostname, int portno)
{
int sockfd, n, serverlen;
struct sockaddr_in serveraddr;
struct sockaddr_in client_addr;
struct hostent *server;
char *buf;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
perror("ERROR opening socket");
server = gethostbyname(hostname);
if (server == NULL)
perror("ERROR, no host found");
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
bcopy((char *)server->h_addr, (char *)&serveraddr.sin_addr.s_addr, server->h_length);
serveraddr.sin_port = htons(portno);
client_addr.sin_family = AF_INET;
client_addr.sin_addr.s_addr = htonl(INADDR_ANY);
client_addr.sin_port = htons(5500);
if (bind(sockfd,(struct sockaddr *)&client_addr, sizeof(struct sockaddr)) == -1)
perror("Socket could not be binded");
if(setsockopt(sockfd,IPPROTO_IP,IP_TOS,&tos,sizeof(tos)))
perror("Could not set socket option");
pthread_t threads[2];
serverlen = sizeof(serveraddr);
struct global_table server_info;
server_info.sockID = sockfd;
server_info.serveraddr = &serveraddr;
pthread_create(&threads[0],NULL,recvFromServer, &server_info); // Trying to recv on a different thread
pthread_join(threads[0],NULL);
}
int main(int argc, char **argv) {
char *hostname;
int portno;
if (argc != 3)
perror("usage: <hostname> <port>\n");
hostname = argv[1];
portno = atoi(argv[2]);
pingServer(hostname, portno);
return 0;
}
How can I fix the problem?
1 Answer 1
In addition to the problems noted in the comments (and by now, this problem is also noted in the comments...), this line
struct global_table server_info;
creates a local variable in your pingServer() function.
This line
pthread_create(&threads[0],NULL,recvFromServer, &server_info); // Trying to recv on a different thread
of code passes the address of that variable to the recvFromServer() function, which will run in a different thread. But then pingServer() immediately returns and the local server_info variable ceases to exist.
One fix is to define the server_info and serveraddr variable as static:
static struct global_table server_info;
static struct sockaddr_in serveraddr;
That will create one copy of the server_info variable that will be shared by every invocation of pingServer(), but that one copy will exist for the lifetime of your program.
3 Comments
struct global_table server_info, but also struct sockaddr_in serveraddr which server_info.serveraddr gets pointed at that would need to be static. And, that would still mean he couldn't later call pingServer() more than once to have more than one thread at a time.
&rec->serveraddrshoudl surely berec->serveraddrstruct global_tablecontains a pointer tostruct sockaddr_in, and you take the address of that pointer to pass torecvfrom()-- that's one too many levels of indirection. Also, you point theserveraddrmember at a struct that's local to thepingServer()function, then try to use it after that function returns (via the thread you created right before returning)... the struct isn't valid anymore then, and you'd have undefined behaviour even if the indirection were correct.server_infolives onpingServer()'s stack which is invalid a wink after thepthread_create()returned. Also the whole process, along with all it's threads ends another wink later, the momentmain()returns. To fix this you could for example add a call topthread_join()after having created the thread.