Reputation: 8951
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
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