bf16
bf16

Reputation: 37

c sockets multiple send/recv calls

I'm learning about c socket programming. I'm very new to this so forgive me if the answer may seem obvious. So basically I want the client to send to the server two strings ( username and a password). Problem is that the server only receives the username and then closes connection.

Can anyone explain why is this happening and how can I get it to work as intended ?

client:

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <signal.h>
#include <ctype.h>          
#include <arpa/inet.h>
#include <netdb.h>

#define PORT 20000
#define LENGTH 512 


void error(const char *msg)
{
    perror(msg);
    exit(1);
}

int main(int argc, char *argv[])
{
    /* Variable Definition */
    int sockfd; 
    int nsockfd;
    char revbuf[LENGTH]; 
    struct sockaddr_in remote_addr;

    /* Get the Socket file descriptor */
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        fprintf(stderr, "ERROR: Failed to obtain Socket Descriptor! (errno = %d)\n",errno);
        exit(1);
    }

    /* Fill the socket address struct */
    remote_addr.sin_family = AF_INET; 
    remote_addr.sin_port = htons(PORT); 
    inet_pton(AF_INET, "127.0.0.1", &remote_addr.sin_addr); 
    bzero(&(remote_addr.sin_zero), 8);

    /* Try to connect the remote */
    if (connect(sockfd, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) == -1)
    {
        fprintf(stderr, "ERROR: Failed to connect to the host! (errno = %d)\n",errno);
        exit(1);
    }
    else 
        printf("[Client] Connected to server at port %d...ok!\n", PORT);

    char username[20], pw[20],buff;
    int rc,rc2;

    printf("username: ");
    scanf("%s",username);  
    rc=send(sockfd, username, strlen(username)+1, 0);
    printf("\n");
    printf("password: ");
    scanf("%s",pw);     
    rc2=send(sockfd, pw, strlen(pw)+1, 0);


    close (sockfd);
    printf("[Client] Connection lost.\n");
    return (0);
}

server:

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <signal.h>
#include <ctype.h>          
#include <arpa/inet.h>
#include <netdb.h>

#define PORT 20000 
#define BACKLOG 5
#define LENGTH 512 

void error(const char *msg)
{
    perror(msg);
    exit(1);
}

int main ()
{
    /* Defining Variables */
    int sockfd; 
    int nsockfd; 
    int num;
    int sin_size; 
    struct sockaddr_in addr_local; /* client addr */
    struct sockaddr_in addr_remote; /* server addr */
    char revbuf[LENGTH]; // Receiver buffer

    /* Get the Socket file descriptor */
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
    {
        fprintf(stderr, "ERROR: Failed to obtain Socket Descriptor. (errno = %d)\n", errno);
        exit(1);
    }
    else 
        printf("[Server] Obtaining socket descriptor successfully.\n");

    /* Fill the client socket address struct */
    addr_local.sin_family = AF_INET; // Protocol Family
    addr_local.sin_port = htons(PORT); // Port number
    addr_local.sin_addr.s_addr = INADDR_ANY; // AutoFill local address
    bzero(&(addr_local.sin_zero), 8); // Flush the rest of struct

    /* Bind a special Port */
    if( bind(sockfd, (struct sockaddr*)&addr_local, sizeof(struct sockaddr)) == -1 )
    {
        fprintf(stderr, "ERROR: Failed to bind Port. (errno = %d)\n", errno);
        exit(1);
    }
    else 
        printf("[Server] Binded tcp port %d in addr 127.0.0.1 sucessfully.\n",PORT);

    /* Listen remote connect/calling */
    if(listen(sockfd,BACKLOG) == -1)
    {
        fprintf(stderr, "ERROR: Failed to listen Port. (errno = %d)\n", errno);
        exit(1);
    }
    else
        printf ("[Server] Listening the port %d successfully.\n", PORT);

    int success = 0;
    while(1)
    {
        sin_size = sizeof(struct sockaddr_in);

        if ((nsockfd = accept(sockfd, (struct sockaddr *)&addr_remote, &sin_size)) == -1) 
        {
            fprintf(stderr, "ERROR: Obtaining new Socket Despcritor. (errno = %d)\n", errno);
            exit(1);
        }
        else 
            printf("[Server] Server has got connected from %s.\n", inet_ntoa(addr_remote.sin_addr));

        int rc,rc2;
        char username[20],pw[20];
        rc = recv(nsockfd, username, strlen(username), 0);
        printf(username);
        rc2 = recv(nsockfd, pw, strlen(pw), 0);

        printf("\n");
        printf(pw);


            success = 1;
            close(nsockfd);
            printf("[Server] Connection with Client closed. Server will wait now...\n");
           // while(waitpid(-1, NULL, WNOHANG) > 0);
        //}
    }
}

Upvotes: 0

Views: 6754

Answers (1)

nullptr
nullptr

Reputation: 11058

In the server: recv(nsockfd, username, strlen(username), 0);.

The third parameter must specify size of the buffer. However, username does not contain any data yet, so strlen(username) is undefined behavior and most probably returns something inappropriate. Use sizeof(username) instead. The same for password.

Also note that recv will read up to 20 bytes from the stream. So, unless username is guaranteed to be always 19 characters + '\0', the first recv may (somewhat unexpectedly) read some characters from password as well, stealing them from the second recv. There are no message boundaries in a TCP stream.

Upvotes: 1

Related Questions