Socket connection refused, but both client and server work independently - c

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.

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
}

Related

I can't figure out why recv isn't saving to a buffer

I am creating a TCP Client that can send messages to the server (using winsock2) and in turn the server sends the message to every other socket, but for some reason it recv() isn't getting the data of it's own message.
#include <stdio.h>
#include <windows.h>
#include <winsock2.h>
#include <time.h>
#include <string.h>
#pragma comment(lib, "ws2_32.lib")
DWORD WINAPI receive(LPVOID s) {
char output[4096];
for(;;) {
recv((SOCKET) s, output, sizeof(output), 0);
printf("%s", output);
}
return 0;
}
int main() {
WSADATA wsa;
SOCKET s;
struct sockaddr_in server;
clock_t start;
double finished;
start = clock();
printf("initializing...\n");
if(WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {
printf("failed: %d", WSAGetLastError());
//sleep(3);
return 1;
}
finished = (double) (clock() - start) / CLOCKS_PER_SEC;
printf("initialized %fs\n", finished);
start = clock();
printf("creating socket...\n");
if((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
printf("socket creation failed: %d", WSAGetLastError());
//sleep(3);
return 1;
}
finished = (double) (clock() - start) / CLOCKS_PER_SEC;
printf("socket created %fs\n", finished);
printf("what ip would you like to connect to: ");
char ip[64];
scanf("%s", ip);
server.sin_addr.s_addr = inet_addr(ip);
server.sin_family = AF_INET;
server.sin_port = htons(8080);
if(connect(s, (struct sockaddr*) &server, sizeof(server)) < 0) {
printf("connect error\n");
return 1;
}
printf("connection to %s was successful\n", ip);
char username[256];
printf("what username would you like to use: ");
scanf(" %[^\n]s", &username);
HANDLE handle = CreateThread(NULL, 0, receive, &s, 0, NULL);
char input[4096];
char buff[4096];
for(;;) {
printf(">: ");
scanf(" %[^\n]s", &input);
sprintf(buff, "%s> %s", username, input);
send(s, buff, sizeof(buff), 0);
}
return 0;
}
The server was programmed in python, although I do not think that is the issue considering it works when I have the recv() right after the send().
You are passing a pointer to a SOCKET s to your thread worker function:
SOCKET s;
// ...
HANDLE handle = CreateThread(NULL, 0, receive, &s, 0, NULL);
That function is treating the passed argument as if it were a SOCKET:
DWORD WINAPI receive(LPVOID s) {
char output[4096];
for(;;) {
recv((SOCKET) s, output, sizeof(output), 0);
printf("%s", output);
}
return 0;
}
So basically you're not reading from the correct file descriptor but some random address.
Dereferencing the pointer inside the worker function should solve that issue:
DWORD WINAPI receive(LPVOID arg) {
SOCKET *s = arg;
char output[4096];
for(;;) {
recv(*s, output, sizeof(output), 0);
printf("%s", output);
}
return 0;
}
Not checking the return value of recv and using printf as if output were guaranteed to be a null-terminated string is also a serious issue. Therefore, I recommend the following code instead:
DWORD WINAPI receive(LPVOID arg) {
SOCKET *s = arg;
char output[4096];
int len;
for(;;) {
len = recv(*s, output, sizeof(output), 0);
if (len > 0)
printf("%.*s", len, output);
}
return 0;
}
That way, output does not have to be null-terminated.

Writing to server returns nothing

the below is a snippet of a chatclient called Marvin, where, given someone saying something like "Hey Marvin, 1+1", the program will send onto the server "Hey user, 2". The issue is, even though the output can print properly client sized, when I attempt to send it to server using write(), the server just gets "Marvin:"
Any ideas on why my write() isn't working? I highlighted the areas where I used write but they're in the second function, halfway through. There are a lot of helper functions, so I cut them down and explained what they usually do.
static int sockfd;
int main(int argc, char **argv) {
if (argc < 2) {
fprintf(stderr, "usage: %s hostname [port number] ...\n", argv[0]);
return(1);
}
//INITIALIZERS
//int sockfd;
fd_set master;
char buf[500];
struct hostent *hp;
struct sockaddr_in peer;
char *name = malloc(MAXHANDLE);
char *todo = malloc(MAXMESSAGE); /*
extern void reply(char *buf, char *name);
extern char *myreadline(struct client *p);
struct client *p = malloc(sizeof(struct client));
extern int tracer(char *str, int start, int len);
extern int choice(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
*/
//HOST
if ((hp = gethostbyname(argv[1])) == NULL) {
fprintf(stderr, "%s: no such host\n", argv[1]);
return(1);
}
if (hp->h_addr_list[0] == NULL || hp->h_addrtype != AF_INET) {
fprintf(stderr, "%s: not an internet protocol host name\n", argv[1]);
return(1);
}
//SOCKET
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
exit(1);
}
memset(&peer, '\0', sizeof peer);
peer.sin_family = AF_INET;
peer.sin_addr.s_addr = INADDR_ANY;
//PORT
if (argc > 2) {
if (!(port = atoi(argv[2])) == 0) {
peer.sin_port = htons(port);
} else {
fprintf(stderr, "%s: port number must be a positive integer\n", argv[0]);
return(1);
}
} else {
peer.sin_port = htons(1234);
}
//SOCKET
peer.sin_addr = *((struct in_addr*)(hp->h_addr));
if (connect(sockfd, (struct sockaddr *)&peer, sizeof(peer)) == -1) {
perror("connect");
close(sockfd);
exit(1);
}
FD_ZERO(&master);
FD_SET(STDIN_FILENO, &master);
FD_SET(sockfd, &master);
fd_set fds;
//BANNER HANDLE
//FILLS *p WITH INFORMATION of server
//*p = addclient(sockfd);
char *buff = malloc(500);
while (1) {
//READS A LINE
//buff = myreadline(p);
if (buff == NULL)
continue;
if (!strcmp(buff, CHATSVR_ID_STRING)) {
write(sockfd, "Marvin", MAXHANDLE);
break;
} else {
fprintf(stderr, "%s: invalid chatsvr\n", buff);
exit(1);
}
}
//LOOP
while(1) {
fds = master;
//RUNS SELECT WITH ERROR CHECKING
choice(sockfd+1, &fds, NULL, NULL, NULL);
if(FD_ISSET(STDIN_FILENO, &fds)) {
fgets(buf, sizeof buf, stdin);
if (strlen(buf) > 0) {
reply(buf, "Marvin");
}
} else if (FD_ISSET(sockfd, &fds)) {
//name = myreadline(p);
if (name != NULL) {
printf("%s\n", name);
strtok_r(name, ": ", &todo);
//tracer(todo, 0, 1);
reply(todo, name);
}
}
}
return(0);
}
//Given name and command, prints required output
void reply(char *buf, char *name) {
//extern int tracer(char *str, int start, int len);
//extern int tinder(const char *a, const char *b);
char *replied = buf;
if (strlen(buf) > 0) {
if (!tinder(buf, "Hey Marvin,")) {
printf("%s\n", replied);
//ISSUE HERE XXX
write(sockfd, replied, sizeof(replied));
return;
} else {
tracer(buf, 0, 11);
}
struct expr *e = parse(buf);
if (e) {
sprintf(replied, "Marvin: Hey %s, %d\n", name, evalexpr(e));
printf("%s\n", replied);
//ISSUE HERE
write(sockfd, replied, sizeof(replied));
freeexpr(e);
} else {
sprintf(replied, "Marvin: Hey %s, I don't like that.\n[%s]\n", name, errorstatus);
printf("%s\n", replied);
//XXX ISSUE HERE
write(sockfd, replied, sizeof(replied));
}
}
}
From client side, I send:
chatsvr: Welcome to our new participant, Marvin
hi
dsha
^C
Server side, this is what shows up:
chatsvr: Welcome to our new participant, Marvin
Marvin:
Marvin:
Marvin:
chatsvr: Goodbye, Marvin
When it should be:
chatsvr: Welcome to our new participant, Marvin
Marvin: hi
Marvin: dsha
chatsvr: Goodbye, Marvin
//ISSUE HERE XXX
write(sockfd, replied, sizeof(replied));
Here you should use strlen(replied) instead of sizeof.
Make sure make the received string is null terminated before you use it as string.

argc not being 2 error

I've been working on a program that was like the one I posted earlier here https://stackoverflow.com/questions/33989328/converting-linked-list-array-client-server-into-single-array except this time I tried to just get the sample code to work making my own program in the process (same basic program but different content) when I get this strange error. In the debugger there is a bit that if argc != 2 it's a usage: client hostname error. I ran it several times and discovered that argc is 1. How do I make argc be 2 and not 1 or 3? There is a client and server program as follows:
edit Now it says connection refused
client:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//define constants
#define SERVER_PORT 6500
#define BUFFER_SIZE 1000
void die(const char*);
void pdie(const char *);
int main (int argc, char *argv[]) {
int sock; // file descriptor (fd) for socket connection
struct sockaddr_in server; // Socket info for server
struct sockaddr_in client; // Socket info about us
int clientLen; // length of client socket struct
struct hostent *hp; // return value from gethostbyname()
char buf[BUFFER_SIZE]; // buffer for message reception from server
int i; // loop counter
if (argc != 2) {
die("Usage: client hostname");
}
for(i = 0; i < 3; i++) {
// Open a socket unbound with type ip/tcp
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
pdie("Opening stream socket");
}
puts("created sock");
// Prepare to connect to server
memset((char*)&server, 0, sizeof(server));
server.sin_family = AF_INET;
if ((hp = gethostbyname(argv[1])) == NULL) {
char msg[100];
sprintf(msg, "%s: unknown host\n", argv[1]);
die(msg);
}
puts("prepared to connect to server");
// set sin_addr struct variables
memcpy(&server.sin_addr, hp->h_addr, hp->h_length);
// IP address should be set to that of the machine running the server
server.sin_addr.s_addr = inet_addr("replace with your ip address");
server.sin_port = htons((u_short) SERVER_PORT);
// Try to connect
socklen_t serverLen = sizeof(server);
if (connect(sock, (struct sockaddr *) &server, serverLen) < 0) {
pdie("connecting stream socket");
}
// Determine what port client is using
clientLen = sizeof(client);
if (getsockname(sock, (struct sockaddr *) &client, &clientLen)) {
pdie("Getting socket name");
}
if (clientLen != sizeof(client)) {
die("getsocketname() overwrote name structure");
}
printf("Client socket has port %hu\n", ntohs(client.sin_port));
// Prepare our buffer for a read
memset(buf, 0, sizeof(buf));
char input[80];
// get initial prompt
read(sock, buf, BUFFER_SIZE);
printf("%s", (char*)buf);
// get user action choice and send to server
scanf("%s", input);
write(sock, (void*)input, strlen(input));
// control for translation choice
if (strncmp(input, "t", 1) == 0) {
// get prompt for word to translate
read(sock, buf, BUFFER_SIZE);
printf("%s", (char*)buf);
// get user word and send to server
scanf("%s", input);
write(sock, (void*)input, strlen(input));
memset(buf, 0, sizeof(buf));
// get translation
read(sock, buf, BUFFER_SIZE);
// output result
if(strncmp((char*)buf, "ERROR", 5) == 0) {
printf("%s\n", (char*)buf);
} else {
printf("%s in Japanese is %s\n", input, (char*)buf);
}
}
// control for add to dictionary choice
else if (strncmp(input, "a", 1) == 0) {
// get prompt for eng word
memset(buf, 0, sizeof(buf));
read(sock, buf, BUFFER_SIZE);
// get eng word from user
printf("%s", (char*)buf);
scanf("%s", input);
// send eng word to server
write(sock, (void*)input, strlen(input));
memset(buf, 0, sizeof(buf));
// get prompt for Japanese word
read(sock, buf, BUFFER_SIZE);
printf("%s", (char*)buf);
scanf("%s", input);
// send Japanese word to server
write(sock, (void*)input, strlen(input));
// get result
memset(buf, 0, sizeof(buf));
read(sock, buf, BUFFER_SIZE);
printf("%s\n", (char*)buf);
}
// Close this connection
close(sock);
}// end for loop
exit(0);
}// end main
// Call perror() to figure out what's going on and die
void pdie(const char *mesg) {
perror(mesg);
exit(1);
}
// Print a message and die
void die(const char *mesg) {
fputs(mesg, stderr);
fputc('\n', stderr);
exit(1);
}
and server
#define _REENTRANT
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/uio.h>
#include <unistd.h>
#include <pthread.h>
// constant declarations
#define TCP_PORT 6500
#define BUFFER_SIZE 1000
// variable declarations
pthread_mutex_t lock;
int serve_count;
// used to store eng word and translation
typedef struct wordpair* wordPairPtr;
struct wordPair
{
char* eng;
char* jap;
wordPairPtr nextPair;
};
typedef struct wordPair wordPair;
// used to store all word pairs in a directory
// implemented as a linked list
struct directory
{
wordPair* dict;
int num_words;
};
typedef struct directory directory;
// function prototypes
void* doKid(void*);
void initializeDirect();
int directAdd(char*, char*);
char* translate(char*);
// global directory variable
directory* d;
main ()
{
// variable declarations
int sockfd;
int newsockfd;
int client;
struct sockaddr_in cli_addr, serv_addr;
pthread_t chld_thr;
initializeDirect();// call function to create directory
puts ("initialized variables");
// build thread attributes
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
puts("set thread attributes");
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
{
fprintf(stderr, "server: can't open stream socket\n");
exit(0);
}
puts("opened stream socket");
// set serv_addr struct variables
memset((char*) &serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(TCP_PORT);
puts("did serv_addr actions");
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0 )
{
fprintf(stderr, "server: can't bind local address\n");
exit(0);
}
puts("bound local address");
// set the level of thread concurrency we desire
pthread_setconcurrency(5);
listen(sockfd, 5);
puts("set thread concurrency");
// begin listening for client requests
puts("awaiting requests");
for(;;)
{
client = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr*) &cli_addr, &client);
if (newsockfd < 0)
{
fprintf(stderr, "server: accept error\n");
exit(0);
}
// create a new thread to process the incoming request
pthread_create(&chld_thr, &attr, doKid, (void*)newsockfd);
puts("Created thread");
// the server is now free to accept another socket request
}
free(d);
puts("now exiting");
return(0);
}// end main
// allocates memory for directory and stores small set of preloaded words and phrases
void initializeDirect()
{
d = (directory*)malloc(sizeof(directory));
if (d == NULL)
{
exit(1);
}
char *eng[20] = {"good morning", "good afternoon", "good evening", "good-bye",
"good night)", "thank you", "no", "yes",
"I'll go and come back", "I'm home", "mother", "father", "older sister", "older brother", "younger sister", "younger brother", "god", "boy", "girl", "spirit"
};
char *jap[20] = {"ohaiyou", "konnichiwa", "konbanwa", "sayonara",
"oyasumi(nasai)", "arigatou", "iie", "hai",
"ittekimasu", "tadaima", "okaasan", "otousan", "oneesan", "oniisan", "imouto", "otouto", "kami", "shoenen", "shoujo", "genki"
};
int i;
for(i = 0; i < 10; i++)
{
directAdd(eng[i], jap[i]);
}
}// end initializeDirect()
// adds a new word pair alphabetically into the directory
int directAdd(char* eng, char* jap)
{
// test for valid arguments
if (eng == NULL || jap == NULL)
{
return (-1);
}
// allocate memory for new wordPair
wordPair *newPair = (wordPair*)malloc(sizeof(wordPair));
if(newPair == NULL)
return(-1);
// assign passed values to new wordPair
newPair->eng = eng;
newPair->jap = jap;
newPair->nextPair = NULL;
// if this is the first wordPair, add it to the front of the linked list
if(d->dict == NULL)
{
d->dict = newPair;
return 0;
}
// otherwise, search directory for correct location for new word pair
wordPair *current = d->dict;
wordPair *previous = NULL;
while(current != NULL && (strcasecmp(current->eng, newPair->eng) < 0))
{
previous = current;
current = current->nextPair;
}
// if the new word is last in the directory, add it there
if(current == NULL)
{
previous->nextPair = newPair;
return 0;
}
// if the english word is already in the directory, return -2
if(strcasecmp(current->eng, newPair->eng) == 0)
{
free(newPair);
return -2;
}
// if the new word is first in the directory, add it there
if(previous == NULL)
{
newPair->nextPair = d->dict;
d->dict = newPair;
return;
}
// if none of the special cases occurred, add the new word
newPair->nextPair = current;
previous->nextPair = newPair;
// advance total count of words
d->num_words++;
// return success
return 0;
}
char* translate(char* eng)
{
// check that our directory is valid
if (d == NULL || d->dict == NULL)
return NULL;
// start searching at the beginning of the directory
wordPair *current = d->dict;
// loop until we find the word or reach the end of the directory
while(current != NULL && strcasecmp(current->eng, eng) < 0)
{
current = current->nextPair;
}
// the word is not in the directory
if(current == NULL)
{
return NULL;
}
// we found the word, return the translation
if( strcasecmp(current->eng, eng) == 0)
{
return strdup(current->jap);
}
// there was an error, return null
return NULL;
}// end translate
// this is the routine that is executed from a new thread
void *doKid(void* arg)
{
int mysocfd = (int) arg;
char buf[BUFFER_SIZE];
char *eng;
char *jap;
char *msg;
int i;
// allocate strings
memset(buf, 0, BUFFER_SIZE);
eng = (char*)malloc(sizeof(char[20]));
jap = (char*)malloc(sizeof(char[20]));
msg = (char*)malloc(sizeof(char[100]));
// build and send intro prompt for client
msg = "Would you like to translate or add a word? (t/a): ";
write(mysocfd, (void*)msg, strlen(msg));
// read from the given socket
read(mysocfd, buf, BUFFER_SIZE);
// if the client wants to translate a word
if(strncmp((char*)buf, "t", 1) == 0)
{
// build and send prompt for word to translate
msg = "Enter the English word you would like to translate to jap: ";
write(mysocfd, (void*)msg, strlen(msg));
// receive word
read(mysocfd, buf, BUFFER_SIZE);
strcpy(eng, buf);
// execute translation
char *trans;
trans = (char*)malloc(sizeof(char[20]));
// lock global variable for read
pthread_mutex_lock(&lock);
trans = translate((char*)buf);
pthread_mutex_unlock(&lock);
// if word was not in directory send error msg to client
if (trans == NULL)
{
msg = "ERROR: word is not in the directory.";
write(mysocfd, (void*)msg, strlen(msg));
}
// if word was translated, send result to client
else
{
write(mysocfd, (void*)trans, strlen(trans));
}
}
// if the client wants to add a word
else if (strncmp((char*)buf, "a", 1) == 0)
{
// build and send prompt for english word
msg = "Enter the English word to add: ";
write(mysocfd, (void*)msg, strlen(msg));
// receive word
read(mysocfd, buf, BUFFER_SIZE);
strcpy(eng, buf);
// build and send prompt for jap translation
memset(buf, 0, sizeof(buf));
msg = "Enter the translation to jap: ";
write(mysocfd, (void*)msg, strlen(msg));
// receive translation
memset(buf, 0, sizeof(buf));
read(mysocfd, buf, BUFFER_SIZE);
strcpy(jap, buf);
// lock global variable for word insertion
pthread_mutex_lock(&lock);
int result = directAdd(eng, jap);
pthread_mutex_unlock(&lock);
// if the add to directory was successful, alert client
if (result == 0)
{
msg = "Added to directory";
}
// if the add to directory was unsuccessful send client error msg
else if (result == -2)
{
msg = "Word is already in directory";
}
else
{
msg = "ERROR.";
}
write(mysocfd, (void*)msg, strlen(msg));
}
// if no valid choice was sent by client, exit thread
else
{
close(mysocfd);
pthread_exit(0);
}
printf("Child[%lu]: Done Processing...\n", pthread_self());
// use a mutex to update the global service counter
pthread_mutex_lock(&lock);
serve_count++;
pthread_mutex_unlock(&lock);
printf("Kid thread [%lu]: The total sockets served = %d\n", pthread_self(), serve_count);
// close the socket and exit this thread
close(mysocfd);
pthread_exit(0);
}// end doKid()

Worker thread exits some time later

Here is a simple echo program using sockets and multi threads, it compiles and runs well in my Ubuntu if the client(via telnet) and server run on the same machine, but when I remotely connect to the server via telnet from another machine, it initially runs well(echos my message back every time), but some time later, there is no echo anymore even the telnet session is still alive, i am not sure where the problem is, can someone give some hits on this? I am new to multi thread programming and socket programming, learning on that.
#define ERROR -1
#define MAX_CLIENTS 2
#define MAX_DATA 1024
void* worker(void* sockId)
{
int socketId = *(int*)sockId;
int data_len = 1;
char data[MAX_DATA];
while(data_len > 0)
{
data_len = recv(socketId, data, MAX_DATA, 0);
if (data_len > 0)
{
send(socketId, data, data_len, 0);
data[data_len] = '\0';
printf("Sent message: %s", data);
}
}
printf("Client disconnected\n");
close(socketId);
}
int main(int argc, char* argv[])
{
if (argc <= 1)
{
printf("missing argument: port\n");
exit(-1);
}
struct sockaddr_in server;
struct sockaddr_in client;
int sock;
int new_connection;
int sockaddr_len = sizeof(struct sockaddr_in);
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == ERROR)
{
perror("server socket: ");
exit(-1);
}
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[1]));
server.sin_addr.s_addr = INADDR_ANY;
bzero(&server.sin_zero, 8);
if ((bind(sock, (struct sockaddr*)&server, sockaddr_len)) == ERROR)
{
perror("bind: ");
exit(-1);
}
if ((listen(sock, MAX_CLIENTS)) == ERROR)
{
perror("listen: ");
exit(-1);
}
while(1)
{
if ((new_connection = accept(sock, (struct sockaddr*)&client, &sockaddr_len)) == ERROR)
{
perror("accpet: ");
exit(-1);
}
printf("New Client connected from port: %d and IP: %s\n", ntohs(client.sin_port), inet_ntoa(client.sin_addr));
pthread_t thread;
pthread_create(&thread, NULL, worker, (void*)&new_connection);
pthread_detach(thread);
}
close(sock);
pthread_exit(NULL);
return 0;
}
Add some logging and you'll probably find that your code is blocked in send. You use naive, sequential I/O, so if the other end of the connection stops reading data, soon you do too.

UDP chat application in C - IP prints as 0.0.0.0

I have created a UDP chat application using state machine pattern but when it needs to print the IP address using inet_ntoa, the terminal displays 0.0.0.0.
Here is my entire code (I am pasting it whole so you can tell me where I can improve it. I started learning C two weeks ago and could REALLY use some advice)
#include <stdio.h> // stdin, fgets(), scanf(), printf()
#include <stdlib.h> // exit()
#include <sys/socket.h> // SOCK_DGRAM
#include <netinet/in.h> // in_addr
#include <arpa/inet.h> // inet_ntoa(), inet_aton()
#include <unistd.h> // select()
#include <string.h> // memset(), strcpy(), strerror()
#include <errno.h> // errno
#include <ctype.h> // isspace()
#define LISTENER_PORT 48879 // our 0xBEEF port :-)
#define BUFFER_SIZE 204 // 200 bytes plus 4 bytes of header
#define STDIN 0 // keyboard input
int chat_socket; // this is the only socket used in the program
typedef struct // struct the protocol
{
unsigned char version; // 1 byte version number
unsigned char command; // 1 byte command type
unsigned char seq; // 1 byte sequence number
unsigned char ack; // 1 byte acknowledgment number
char data[BUFFER_SIZE]; // 200 bytes message limit
} Packet;
Packet rxPacket; // received packet instance
Packet txPacket; // sent packet instance
enum states // enumerate the states
{
START, // Send request to remote IP or wait for a request (WAIT_CONN_REQ)
WAIT_RESP, // Chat request sent to remote IP. Waiting for a response from the target machine
SEND_CONN_RESP, // Chat request received from remote IP. ACCEPT or REJECT
ACCEPTED, // Both parties agreed to exchange datagrams. Begin application data (MESSAGES) exchange
STOP
};
typedef enum states states;
states state;
struct sockaddr_in my_address;
struct sockaddr_in sender_address;
struct sockaddr_in dest_address;
ssize_t r;
socklen_t sockLen = sizeof(struct sockaddr_in);
int WAIT_CONN_REQ(char *argv[])
{
/* Bind the socket to the given port */
if (bind(chat_socket, (struct sockaddr *)&my_address, sizeof(my_address))<0)
{
printf("UDP socket bind() error no %d: %s\n", errno, strerror(errno));
exit(1);
}
printf("Socket bound to port %d!\nWaiting for CONN_REQ!\n", LISTENER_PORT);
if (((r = recvfrom(chat_socket, &rxPacket, BUFFER_SIZE, 0, (struct sockaddr *)&sender_address, &sockLen)))<0)
{
printf("UDP recvfrom() error no %d: %s\n", errno, strerror(errno));
exit(1);
}
if (rxPacket.command == 1)
{
int rsp = 0;
char q = 0;
while (q != 'A' && q != 'D')
{
printf("Connection request received from %s - [A]ccept or [D]ecline?\t", inet_ntoa(sender_address.sin_addr));
scanf(" %c", &q);
}
if (q == 'A')
{
printf("You have accepted the connection request.\n");
rsp = 3;
}
else if (q == 'D')
{
printf("You have declined the connection request.\n");
rsp = 2;
}
if (rsp != 0)
{
strcpy(txPacket.data, "Name");
txPacket.version = 1;
txPacket.command = rsp;
sendto(chat_socket, &txPacket, BUFFER_SIZE, 0, (struct sockaddr *)&sender_address, sizeof(sender_address));
state = ACCEPTED;
}
}
return(0);
}
void lookup(FILE *names, struct sockaddr_in myip[])
{
char ipNr[32];
char chatName[32];
while(!feof(names))
{
fscanf(names, "%[^;];%s\n", ipNr, chatName);
if (strcmp(ipNr, (const char*) myip) == 0)
{
printf("Found your IP in database\n");
printf("IP: %s\n", ipNr);
printf("Username: %s\n", chatName);
printf("---\n");
return;
}
}
}
void SEND_CONN_REQ(char *argv[])
{
strcpy(txPacket.data, "Name");
txPacket.version = 1;
txPacket.command = 1;
printf("Dest IP is %s\n", argv[0]);
inet_aton(argv[0], &dest_address.sin_addr);
sendto(chat_socket, &txPacket, BUFFER_SIZE, 0, (struct sockaddr *)&dest_address, sizeof(dest_address));
printf("Chat request sent to %s - Waiting for a response\n", inet_ntoa(dest_address.sin_addr));
state = WAIT_RESP;
}
void initialise()
{
memset(&my_address.sin_zero, 0, sizeof(my_address.sin_zero));
memset(&dest_address.sin_zero, 0, sizeof(dest_address.sin_zero));
memset(&sender_address.sin_zero, 0, sizeof(sender_address.sin_zero));
my_address.sin_family = AF_INET;
my_address.sin_addr.s_addr = INADDR_ANY;
my_address.sin_port = htons(LISTENER_PORT);
dest_address.sin_family = AF_INET;
dest_address.sin_port = htons(LISTENER_PORT);
if ((chat_socket = socket(AF_INET, SOCK_DGRAM, 0))<0)
{
printf("UDP socket allocation error no %d: %s\n", errno, strerror(errno));
exit(1);
}
}
void DATA_XCHANGE()
{
while (1)
{
txPacket.version = 1;
txPacket.command = 0;
int len = sizeof(sender_address);
fd_set readSet;
FD_ZERO(&readSet);
FD_SET(STDIN, &readSet);
FD_SET(chat_socket, &readSet);
if ((select(32, &readSet, NULL, NULL, NULL))>0)
{
if (FD_ISSET(STDIN, &readSet))
{
fgets(txPacket.data, BUFFER_SIZE, stdin);
if (isspace(*txPacket.data) == 0)
{
printf("You: %s", txPacket.data);
sendto(chat_socket, &txPacket, BUFFER_SIZE, 0, (struct sockaddr *)&sender_address, sizeof(sender_address));
}
}
else if (FD_ISSET(chat_socket, &readSet))
{
if (((r = recvfrom(chat_socket, &rxPacket, BUFFER_SIZE, 0, (struct sockaddr *)&sender_address, (socklen_t *)&len)))<0)
{
printf("UDP recvfrom() error no %d: %s\n", errno, strerror(errno));
exit(1);
}
if (rxPacket.command == 0)
{
printf("message: %s", rxPacket.data);
}
}
}
}
}
int main(int argc, char *argv[])
{
initialise();
printf("your ip is %s", inet_ntoa(my_address.sin_addr));
char *fname = "names.db";
FILE *names = fopen(fname, "r");
lookup(names, &my_address);
state = START;
while (state != STOP)
{
switch (state)
{
case START:
printf("Simple Chat Client - START state\n");
if (argv[1] != NULL)
{
SEND_CONN_REQ(&argv[1]);
}
else
{
WAIT_CONN_REQ(&argv[1]);
}
break;
case WAIT_RESP:
printf("WAIT_RESP STATE!\n");
if (((r = recvfrom(chat_socket, &rxPacket, BUFFER_SIZE, 0, (struct sockaddr *)&sender_address, &sockLen)))<0)
{
printf("UDP recvfrom() error no %d: %s\n", errno, strerror(errno));
exit(1);
}
if (rxPacket.command == 3)
{
printf("Your connection request was accepted.\n");
state = ACCEPTED;
}
else if (rxPacket.command == 2)
{
printf("Your connection request was declined.\n");
state = STOP;
}
break;
case SEND_CONN_RESP:
printf("SEND_CONN_RESP state!\n");
break;
case ACCEPTED:
printf("ACCEPTED state!\n");
DATA_XCHANGE();
break;
case STOP:
printf("STOPPED! (switch)\n");
break;
}
}
printf("STOPPED! main()\n");
}
The printf() right below initialise() in the main() function is where it prints 0.0.0.0
Again, I would VERY MUCH appreciate any coding advice at this point. It helps the learning process!
Your program is doing exactly what it's supposed to.
0.0.0.0 is the value of INADDR_ANY -- in other words, bind to all available interfaces.
When you set it here:
my_address.sin_addr.s_addr = INADDR_ANY;
you're setting it to 0, and telling it to bind to anything it can.

Resources