1

I have been working on this for a while trying to learn socket programming but am running into some probably bone-headed problems.

The problem that I am trying to solve is sending 3 identical sends from the client to the server for the purpose of registering the client. At this point I have one of the sends and receives working but am not able to get the second or third to work. For debugging purposes I am printing the data field of my packet struct and, while it prints for the first receive, the second receive is blank and the third receive is an odd squiggly box followed by an equals sign. I think I am getting stuck in the first receive maybe but I am really not sure what the issue is.

In the following code I have attempted to send the same packet over 3 times, and have also tried what I currently have below, sending 3 different packets that should all contain the same info, the result is always the same.

Here is the code for the client:

#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>

#define SERVER_PORT 5654
#define MAX_LINE 256

/*structure of the packet*/
struct packet{
    short type;
    char data[MAX_LINE];
};

int main(int argc, char* argv[])
{

    struct packet packet_reg;
    struct packet packet_reg2;
    struct packet packet_reg3;
    struct hostent *hp;
    struct sockaddr_in sin;
    char *host;
    char buf[MAX_LINE];
    int s;
    int len;
    char hostname[1024];
    hostname[1023] = '\0';

    if(argc == 2){
        host = argv[1];
    }
    else{
        fprintf(stderr, "usage:newclient server\n");
        exit(1);
    }

    /* translate host name into peer's IP address */
    hp = gethostbyname(host);
    if(!hp){
        fprintf(stderr, "unkown host: %s\n", host);
        exit(1);
    }

    /* active open */
    if((s = socket(PF_INET, SOCK_STREAM, 0)) < 0){
        perror("tcpclient: socket");
        exit(1);
    }

    /* build address data structure */
    bzero((char*)&sin, sizeof(sin));
    sin.sin_family = AF_INET;
    bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
    sin.sin_port = htons(SERVER_PORT);


    if(connect(s,(struct sockaddr *)&sin, sizeof(sin)) < 0){
        perror("tcpclient: connect");
        close(s);
        exit(1);
    }
    /* main loop: get and send lines of text */
    while(fgets(buf, sizeof(buf), stdin)){

        gethostname(hostname, 1023);
        printf("Hostname: %s\n", hostname);

        packet_reg.type = htons(121);
        strcpy(packet_reg.data,hostname);

        /*send the registration packet to the server*/
        if(send(s,&packet_reg,sizeof(packet_reg),0)<0){
            printf("\nsend failed\n");
            exit(1);
        }

        packet_reg2.type = htons(121);
        strcpy(packet_reg2.data,hostname);

        printf("%s\n",packet_reg2.data );

        /*send the registration packet to the server*/
        if(send(s,&packet_reg2,sizeof(packet_reg2),0)<0){
            printf("\nsend failed\n");
            exit(1);
        }

        packet_reg3.type = htons(121);
        strcpy(packet_reg3.data,hostname);

        /*send the registration packet to the server*/
        if(send(s,&packet_reg3,sizeof(packet_reg3),0)<0){
            printf("\nsend failed\n");
            exit(1);
        }

    }
}

Here is the code for the server, I have done the same thing with trying to print the same packet and replace the information in it as well as use 3 different packets.

#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
#include<string.h>
#include<stdlib.h>

#define SERVER_PORT 5654
#define MAX_LINE 256
#define MAX_PENDING 5

/*structure of the packet*/
struct packet{
    short type;
    char data[50];
};

int main(int argc, char* argv[])
{

    struct packet packet_reg;
    struct packet packet_reg2;
    struct packet packet_reg3;
    struct sockaddr_in sin;
    struct sockaddr_in clientAddr;
    char buf[MAX_LINE];
    int s, new_s;
    int len;




    /* setup passive open */
    if((s = socket(PF_INET, SOCK_STREAM, 0)) < 0){
        perror("tcpserver: socket");
        exit(1);
    }


    /* build address data structure */
    bzero((char*)&sin, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = INADDR_ANY;
    sin.sin_port = htons(SERVER_PORT);


    if(bind(s,(struct sockaddr *)&sin, sizeof(sin)) < 0){
        perror("tcpclient: bind");
        exit(1);
    }
    listen(s, MAX_PENDING);

    /* wait for connection, then receive and print text */
    while(1){
        if((new_s = accept(s, (struct sockaddr *)&clientAddr, &len)) < 0){
            perror("tcpserver: accept");
            exit(1);
        }

        printf("\n Client's port is %d \n", ntohs(clientAddr.sin_port)); 


        if(recv(new_s,&packet_reg,sizeof(packet_reg),0)<0){
            printf("\ncouldnt receive first reg packet\n");
            exit(1);
        }
        printf("%s\n",packet_reg.data );


        if(recv(new_s,&packet_reg2,sizeof(packet_reg2),0)<0){
            printf("\not recieved second reg packet\n");

            exit(1);
        }
        printf("%s\n",packet_reg2.data );


        if(recv(new_s,&packet_reg3,sizeof(packet_reg3),0)<0){
            printf("\ncouldnt receive first reg packet\n");
            exit(1);
        }
        printf("%s\n",packet_reg3.data );



    }
}

Any help on this would be greatly appreciated. I am sure it is a dumb error and that I am just not understanding how it works. First time using c.

1
  • You're assuming that every recv() fills the buffer. It isn't obliged to do that. You have to loop. You're also not checking for end of stream, and you're not closing any sockets. Commented Feb 10, 2016 at 3:30

1 Answer 1

5

So one confusion you have is that you don't have a packet socket -- you're using SOCK_STREAM so you have a stream socket, which transfers a stream of bytes not packets. Each send and recv call can send or receive any amount of bytes, and there's not necessarily any connection between the sizes -- bytes sent in multiple sends might be received together in a single recv or bytes in a single send might be split up in mulitple receives.

This leads immediately to your main problem -- your client is sending 258 byte "packets", while your server is reading 52 byte "packets". So your first recv gets at most 52 bytes of the first send, and the second recv gets the following bytes from the middle of that first send (likely random uninitialized garbage). It is probable that the recv calls all return the full 52 bytes, but not guarenteed.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, I changed the size of the recieving packet to the same size size of the sending one and that fixed the issue. I knew it was a dumb mistake. Thank you for helping me learn.
Note that you still have no guarentee that either the send or recv calls won't return less than the number of bytes requested -- the socket buffer may fill up (leading to a short send) or the network layer may insert packet boundaries at different points, leading to a short recv. You need to check the return values and act appropriately.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.