123
123

Reputation: 8951

Socket connection refused, but both client and server work independently

I've implemented a network chat client in C that looks like this:

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "stdbool.h"
#include "sys/socket.h"
#include "sys/types.h"
#include "netdb.h"
#include "netinet/in.h"
#include "pthread.h"
#include "errno.h"

#define MESSAGE_BUFFER 500
#define USERNAME_BUFFER 10

typedef struct {
    char* prompt;
    int socket;
} thread_data;


// Connect to server
void * connect_to_server(int socket_fd, struct sockaddr_in *address) {
    int response = connect(socket_fd, (struct sockaddr *) address, sizeof *address);
    if (response < 0) {
        fprintf(stderr, "socket() failed: %s\n", strerror(errno));
        printf("Failed to connect\n");
        exit(1);
    } else {
      printf("Connected\n");
    }
}

// Get message from stdin and send to server
void * send_message(char prompt[USERNAME_BUFFER+4], int socket_fd, struct sockaddr_in *address) {
  printf("%s", prompt);
  char message[MESSAGE_BUFFER];
  char final_message[MESSAGE_BUFFER+USERNAME_BUFFER+1];
  while (fgets(message, MESSAGE_BUFFER, stdin) != NULL) {
      memset(final_message,0,strlen(final_message)); // Clear final message buffer
      strcat(final_message, prompt);
      strcat(final_message, message);
      printf("\n%s", prompt);
      if (strncmp(message, "/quit", 5) == 0) {
        printf("Closing connection...\n");
        exit(0);
      }
      sendto(socket_fd, final_message, MESSAGE_BUFFER+USERNAME_BUFFER+1, 0, (struct sockaddr *) &address, sizeof address);
  }
}

void * receive(void * threadData) {
    int socket_fd, response;
    char message[MESSAGE_BUFFER];
    thread_data* pData = (thread_data*)threadData;
    socket_fd = pData->socket;
    char* prompt = pData->prompt;
    memset(message, 0, MESSAGE_BUFFER); // Clear message buffer

    // Print received message
    while(true) {
        response = recvfrom(socket_fd, message, MESSAGE_BUFFER, 0, NULL, NULL);
        if (response) {
            printf("\nServer> %s", message);
            printf("%s", prompt);
            fflush(stdout); // Make sure "User>" gets printed
        }
    }
}

int main(int argc, char**argv) {
    long port = strtol(argv[2], NULL, 10);
    struct sockaddr_in address, cl_addr;
    char * server_address;
    int socket_fd, response;
    char prompt[USERNAME_BUFFER+4];
    char username[USERNAME_BUFFER];
    pthread_t thread;

    // Check for required arguments
    if (argc < 3) {
        printf("Usage: client ip_address port_number\n");
        exit(1);
    }

    // Get user handle
    printf("Enter your user name: ");
    fgets(username, USERNAME_BUFFER, stdin);
    username[strlen(username) - 1] = 0; // Remove newline char from end of string
    strcpy(prompt, username);
    strcat(prompt, "> ");

    server_address = argv[1];
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = inet_addr(server_address);
    address.sin_port = port;
    socket_fd = socket(AF_INET, SOCK_STREAM, 0);

    connect_to_server(socket_fd, &address);

    // Create data struct for new thread
    thread_data data;
    data.prompt = prompt;
    data.socket = socket_fd;

    // Create new thread to receive messages
    pthread_create(&thread, NULL, receive, (void *) &data);

    // Send message
    send_message(prompt, socket_fd, &address);

    // Close socket and kill thread
    close(socket_fd);
    pthread_exit(NULL);
    return 0;
}

This works perfectly fine with a server that I wrote for it. However, when I try to make it play nicely with a server in another language, or one that someone else wrote, things fall apart, and I can't establish a connection. Shouldn't these work independently from each other? If both work separately, they should work together, from what I gather.

For example, if I try to use my client with the server in the answer to this question, things no longer work. I've tested both of them, and they work fine separately, just not together. I've looked at the output of stderr when connecting, but all I get is a Connection refused error with no more information.

Is there something obvious I'm missing trying to get these to work together? If someone could demonstrate how my client could work with the example server, that would be super helpful.

Upvotes: 0

Views: 151

Answers (1)

user207421
user207421

Reputation: 311021

address.sin_port = port;

The problem is here. It should be

address.sin_port = htons(port);

in both client and server.

There are other problems.

fprintf(stderr, "socket() failed: %s\n", strerror(errno));

This should be

fprintf(stderr, "connect() failed: %s\n", strerror(errno));

Then:

sendto(socket_fd, final_message, MESSAGE_BUFFER+USERNAME_BUFFER+1, 0, (struct sockaddr *) &address, sizeof address);

This should be:

send(socket_fd, final_message, strlen(final_message)+1, 0);

You don't need sendto(), as you are already connected, and you don't need to send anything beyond the trailing null. As a matter of fact you can reduce the entire method to this:

void * send_message(char prompt[USERNAME_BUFFER+4], int socket_fd, struct sockaddr_in *address) {
  printf("%s", prompt);
  char message[MESSAGE_BUFFER];
  while (fgets(message, MESSAGE_BUFFER, stdin) != NULL) {
      if (strncmp(message, "/quit", 5) == 0) {
        printf("Closing connection...\n");
        close(socket_fd);
        exit(0);
      }
      send(socket_fd, prompt, strlen(prompt), 0);
      send(socket_fd, message, strlen(message)+1, 0);
      printf("\n%s", prompt);
  }

}

Then:

  if (response) {
        printf("\nServer> %s", message);
        printf("%s", prompt);
        fflush(stdout); // Make sure "User>" gets printed
    }

That should be:

  if (response == -1) {
    fprintf(stderr, "recv() failed: %s\n", strerror(errno));
    break;
  } else if (response == 0) {
        printf("\nPeer disconnected\n");
        break;
  } else {
        printf("\nServer> %s", message);
        printf("%s", prompt);
        fflush(stdout); // Make sure "User>" gets printed
  }

Upvotes: 1

Related Questions