Hassan Abbas
Hassan Abbas

Reputation: 1316

How to receive and send in different threads with C sockets

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?

Upvotes: 0

Views: 1287

Answers (1)

Andrew Henle
Andrew Henle

Reputation: 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.

Upvotes: 1

Related Questions