2

I am having difficulty changing the amount of data my server sends and getting it to send data. This code fails, but works when I change the size of buffer to 16 characters.

This is the code from transferclient.c

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

#define BUFSIZE 218

int main(int argc, char **argv) {
  unsigned short portno = 10823;

    int sock = 0;
    struct sockaddr_in serv_addr;
    char buffer[32] = {0};
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        printf("\n Socket creation error \n");
        return -1;
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(portno);
    printf("Attemping to connect\n");
    if (connect(sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
    {
        printf("\nConnection Failed \n");
        return -1;
    }
    printf("Connected\n");
    read(sock, buffer, 16);
    return 0;
}

This is the code from transferserver.c

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

#define BUFSIZE 218

int main(int argc, char **argv) {
  int portno = 10823;          /* port to listen on */

    int server_fd, new_socket;
    struct sockaddr_in address;
    int opt =1;
    int addrlen = sizeof(address);

    // Creating socket file descriptor
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
    {
        perror("socket failed");
      exit(EXIT_FAILURE);
    }

    // Attaching the socket to the port
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)))
    {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
    
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(portno);
   
   
    // Forcefully attaching socket to the port
    if (bind(server_fd, (struct sockaddr *) &address, sizeof(address))<0)
    {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }
    printf("Listening\n");
    
    while ((new_socket = accept(server_fd, (struct sockaddr *) &address, (socklen_t*) &addrlen)) > 0)
    {
        printf("%d\n", new_socket);
        printf("Socket connected\n");
    }
    return 0;
}

Server side

Listening

4

Socket connected


***Client Side***
``` 
Attemping to connect

Connected

When I change the line in transferclient.c to 32 bytes.

char buffer[32] = {0};

The sockets fail to connect.

Server side

Listening

Client Side

Attemping to connect

Why is that?

Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39
  • 2
    I suspect that the problem is somewhere in the code that you are not showing us. Please provide a [mre]. – Andreas Wenzel Sep 04 '21 at 18:36
  • According to the output that you posted in your question, neither `"Connected"` nor `"\nConnection Failed \n"` gets printed. Are you sure that is correct? If so, does your program crash? – Andreas Wenzel Sep 04 '21 at 18:41
  • Yes that is correct. It seems like the socket starts to connect and gets hung. –  Sep 04 '21 at 18:43
  • I suggest that you change `printf("Connected");` to `printf("Connected\n");` (add newline character). Or you should add an `fflush( stdout );` after that statement. If you don't make sure that the message gets flushed from the output buffer, then you may never see it, for example if the program enters an infinite loop afterwards. See [this question](https://stackoverflow.com/q/1716296/12149471) for more information. An alternative would be to use `stderr` instead of `stdout` for the diagnostic messages, because that stream is normally unbuffered. – Andreas Wenzel Sep 04 '21 at 18:45
  • Neither of those helped. The output is still the same as before. –  Sep 04 '21 at 18:49
  • If you can't provide a [mre], then please at least show us all the code between printing `"Attemping to connect"` and `"Connected"`. Currently you are not showing us the `printf` statement which prints `"Attemping to connect"`. – Andreas Wenzel Sep 04 '21 at 19:02
  • If changing the size of an array causes the behavior of the program to change significantly, then this could be a symptom of the stack getting corrupted. If you are using gcc or clang compiler, then you may want to compile your code with [`fsanitize=address`](https://clang.llvm.org/docs/AddressSanitizer.html), so that the compiler will add some additional runtime tests, to see if this is happening. – Andreas Wenzel Sep 04 '21 at 19:09
  • I included where the print statement is for attempting to connect and I already have that compiler option added as well. –  Sep 04 '21 at 19:11
  • 1
    If you need debugging help, a [mcve] is mandatory. – n. m. could be an AI Sep 04 '21 at 19:16
  • Could you post the code for declaring and initializing serv_code. – cup Sep 04 '21 at 19:25
  • How long did you wait for `connect` to return? If the server is not reacting to the connection request, then it may take about a minute (maybe longer, depending on your operating system) for `connect` to timeout and report failure. However, this behavior should have nothing to do whether the array size is 16 or 32. – Andreas Wenzel Sep 04 '21 at 19:32
  • I have included the minimal viable code. –  Sep 04 '21 at 20:12

2 Answers2

1

In the client code, you don't seem to be setting all fields of serv_addr.

struct sockaddr_in serv_addr;

[...]

serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(portno);

Because you are not setting serv_addr.sin_addr, it will have an indeterminate (garbage) value when you pass it to the function connect.

My guess is that changing the size of the array caused the sin_addr field of serv_addr to have a different initial (garbage) value. That is why the code works when buffer has a size of 16 but fails when it has a size of 32.

Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39
1

In my opinion... apart of what has already been mentioned in other answers, you are lacking constants... you should define something like:

#define BUFFER_SIZE    (32)

and then use

    char buffer[BUFFER_SIZE];

and

    read(sock, buffer, BUFFER_SIZE);

or, if you don't like this approach, use this other:

    char buffer[32];

and later

    read(sock, buffer, sizeof buffer);

but if you put different numbers in the buffer size and in the read() call it is normal that it doesn't work ok when you call read() with 16 as the number of characters to read.

By the way, it is common that you ask a socket to read a fixed amount of bytes, and it returns less bytes than the amount you requested, so IT IS VERY IMPORTANT THAT YOU CHECK THE RETURN VALUE OF read(2). Something like:

    ssize_t n = read(sock, buffer, BUFFER_SIZE);

as from buffer[n] to buffer[sizeof buffer - 1] there can be nothing useful to your code (rests of a previous read, or similar) It is quite common to print it with something like:

    if (n > 0)
        printf("Read: [%.*s]\n", n, buffer);

that will print that number of received valid characters, and not what is behind them in the buffer.

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31