Sending and Receiving a struct over TCP Socket in Linux

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • shravansofts
    New Member
    • Apr 2012
    • 3

    Sending and Receiving a struct over TCP Socket in Linux

    hi Mates,

    First of all thanks for this wonderful Programmers Community.

    Recently i started to learn Socket Programming. i have some doubts, hope u ppl will clarif them.

    i am trying to code a C program for sending a struct over TCP Socket in Linux!
    The code is as follows:
    Code:
    /*
    ** sravan_server.c - a stream socket (TCP) server Program 
    */
    #include <stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<errno.h>
    #include<string.h>
    #include<sys/types.h>
    #include<sys/socket.h>
    #include<netinet/in.h>
    #include<arpa/inet.h>
    #include<sys/wait.h>
    #include<signal.h>
    #include <time.h> 
    
    #define MYPORT 3490	// the port users will be connecting to
    #define BACKLOG 10	// how many pending connections queue will hold
    
    void sigchld_handler(int s)
    {
    while(wait(NULL) > 0);
    }
    
    // Structure to be sent over TCP Socket
    struct RTUDATA
    {
      unsigned short tagid;
      unsigned char flag;
      float value;
      time_t time_stamp;
    };
    
    int main(void)
    {
    int sockfd, new_fd;		// listen on sock_fd, new connection on new_fd
    struct sockaddr_in my_addr;	// Sender's address information
    struct sockaddr_in their_addr;	// connector’s address information
    int sin_size;
    struct sigaction sa;
    int yes=1;
    
    //char *str="Hello 4rm_MTU!\n";
    
    int n=0;
    time_t ticks;
    ticks = time(NULL);
    struct RTUDATA rtu={htons(0x123), 'y', htons(33.3), ctime(&ticks)};
    
    
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    perror("socket");
    exit(1);
    }
    if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
    perror("setsockopt");
    exit(1);
    }
    my_addr.sin_family = AF_INET;		//host byte order
    my_addr.sin_port = htons(MYPORT);	//short, network byte order
    my_addr.sin_addr.s_addr = INADDR_ANY;	//automatically fill with my IP
    memset(&(my_addr.sin_zero),'\0', 8);	//zero the rest of the struct
    
    
    if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))== -1)
    {
    perror("bind");
    exit(1);
    }
    
    if (listen(sockfd, BACKLOG) == -1) {
    perror("listen");
    exit(1);
    }
    
    sa.sa_handler = sigchld_handler; // clear all dead processes
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
    perror("sigaction");
    exit(1);
    }
    while(1) {	// main accept() loop
    sin_size = sizeof(struct sockaddr_in);
    
    if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr,&sin_size)) == -1) 
    {
    perror("accept");
    continue;
    }
    
    printf("server: got connection from %s\n",inet_ntoa(their_addr.sin_addr));
    
    printf("Data to be transferred is: %d\n",sizeof(rtu));
    
    if (!fork()) {		// this is the child process
      close(sockfd);	// child doesn’t need the listener
    /*
      if (send(new_fd, str, 15, 0) == -1)
        perror("send");
    */
    n=send(new_fd,(void *) &rtu ,sizeof(rtu), 0);
    if ( n== -1)
        perror("send");
    else 
        printf("Total Data sent to %s is: %d \n",inet_ntoa(their_addr.sin_addr), n);
      close(new_fd);
      exit(0);
    }	// child process if condition close 
    close(new_fd);	// parent doesn’t need this
    }	// while loop close
    
    return 0;
    }
    My Question is How to receive this data i.e Client.c Program:
    I tried some thing like below, but it is giving Segmentation Error.
    Code:
    /*
    ** sravan_client.c - a stream socket (TCP) server Program
    */
    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<errno.h>
    #include<string.h>
    #include<netdb.h>
    #include<sys/types.h>
    #include<netinet/in.h>
    #include<sys/socket.h>
    #define PORT 3490 // the port client will be connecting to
    #define MAXDATASIZE 1024 // max number of bytes we can get at once
    int main(int argc, char *argv[])
    {
    int sockfd, numbytes;
    char buf[MAXDATASIZE];
    
    struct hostent *he;
    struct sockaddr_in their_addr; // connector’s (Sender's) address information
    if (argc != 2) {
    fprintf(stderr,"usage: client hostname\n");
    exit(1);
    }
    if ((he=gethostbyname(argv[1])) == NULL) {
    perror("gethostbyname");
    exit(1);
    }
    // get the host info
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    perror("socket");
    exit(1);
    }
    their_addr.sin_family = AF_INET;	// host byte order
    their_addr.sin_port = htons(PORT);	// short, network byte order
    their_addr.sin_addr = *((struct in_addr *)he->h_addr);
    memset(&(their_addr.sin_zero),'\0', 8);	// zero the rest of the struct
    if (connect(sockfd, (struct sockaddr *)&their_addr,
    sizeof(struct sockaddr)) == -1) {
    perror("connect");
    exit(1);
    }
    /*
    if ((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
    perror("recv");
    exit(1);
    }
    */
    
    struct recvrtu
    {
      unsigned short tagid;
      unsigned char flag;
      float value;
      time_t time_stamp;
    }rtu;
    
    //RECEIVING DATA
    if ((numbytes=recv(sockfd, (struct recvrtu *)&rtu, sizeof(rtu), 0)) == -1) {
    perror("recv");
    exit(1);
    }
    
    printf("%d :: %c :: %d :: %s",ntohs(rtu.tagid),rtu.flag,ntohs(rtu.value),rtu.time_stamp);
    
    
    close(sockfd);
    return 0;
    }
    Please tell me the mistakes in the sending and receving programs!
  • Banfa
    Recognized Expert Expert
    • Feb 2006
    • 9067

    #2
    You shouldn't send structures, you can never be sure that the structure padding use by the sending machine will be the same as the structure padding used by the receiving machine.

    Always split your structure down to its basic types including if required splitting down an sub-structures in the structure. Then serialise those values into a byte array using network byte ordering (which is big endian which is different to the byte ordering of intel machines).

    Then you transmit the buffer.

    Then when you receive you have to take account of nature of the TCP connection. A TCP connection is a byte stream, you do not send packets, you queue a buffer of data for transmission and the TCP stack sends the bytes in that buffer as it chooses. The bytes pop out the other end in the right order and with the correct value (if they pop out at all which they wont if, for example, the link is physically broken).

    This means that you might send 2 structures each of 11 bytes but depending on timing and the transport medium the receiving end might receive 1 chunk of 22 bytes, 2 chunks of 11 bytes, 22 chunks of 1 byte or any other combination you can think of that adds up to 44. You receiving software has to be able to handle this and reconstitute the bytes back into your structure.

    That means that unless you are only ever transmitting the 1 structure you will need some way to identify the nature and length of the data being received, say a byte to indicate what structure is being sent and a couple of bytes to give the length of data being sent for that structure.

    Comment

    • shravansofts
      New Member
      • Apr 2012
      • 3

      #3
      is it possible to write the code for me plz?
      it is urgent!

      Comment

      • weaknessforcats
        Recognized Expert Expert
        • Mar 2007
        • 9214

        #4
        We can provide advice and a certain amount of theory and debugging but we cannot provide complete code solutions.

        Comment

        • Banfa
          Recognized Expert Expert
          • Feb 2006
          • 9067

          #5
          But if you look up "Beej's Guide to Network Programming" you will find a lot of useful examples.

          Comment

          Working...