Sockets TCP 2-way connection - c

I'm trying to write a program in TCP where both client and server side are able to communicate until either one sends quit, which terminates the connection. Right now, the client side is able to send stuff, but when the server side sends something, there is a seg fault on the client side. Apologies in advance if my code in not up to par as I am fairly new to coding. Any help would be greatly appreciated
here is my code:
//Client side:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define SERVER_PORT 5432
#define MAX_LINE 256
int main(int argc, char * argv[])
{
struct hostent *hp;
struct sockaddr_in serv_addr;
char *host;
char buf[MAX_LINE];
int n, size;
int sockfd;
if (argc == 2) {
host = argv[1];
}
else {
fprintf(stderr, "usage: simplex-talk host\n");
exit(1);
}
hp = gethostbyname(host);
if (!hp) {
fprintf(stderr, "error: can't find such host: %s\n", host);
exit(1);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)hp->h_addr,(char *)&serv_addr.sin_addr.s_addr,hp->h_length);
serv_addr.sin_port = htons(SERVER_PORT);
size = sizeof(serv_addr);
//active open
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd <0) {
error("ERROR opening socket");
exit(1);
}
printf("successfully opened socket\n");
int quit = 1;
while(quit == 1)
{
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
perror("ERROR: could not connect\n");
close(sockfd);
exit(1);
}
fgets(buf, sizeof(buf), stdin);
if(strcmp(buf, "quit\n") == 0)
{
quit = 0;
int send;
send = sendto(sockfd, buf, MAX_LINE, 0, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (send < 0)
error("ERROR: couldn't send data\n");
break;
}
int send;
send = sendto(sockfd, buf, MAX_LINE, 0, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
if (send < 0)
error("ERROR: couldn't send data to server\n");
//receive data from server
send = recvfrom(sockfd, buf, MAX_LINE, 0, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
if(send < 0)
error("ERROR: couldn't receive from socket\n");
if(strcmp(buf, "quit\n") == 0)
quit = 0;
else
fputs(buf, stdout); //print what is received
}
}
This is the server side:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define MAX_LINE 1024
void error(char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int clilen;
if (argc < 2)
{
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
portno = atoi(argv[1]);
//create a socket
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
clilen = sizeof(serv_addr);
if (sockfd < 0)
{
error("ERROR opening socket");
}
//bind address to socket
if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
error("ERROR: could not bind");
//listen for connection request
listen(sockfd,5);
int quit = 1;
while(quit == 1)
{
if((newsockfd = accept(sockfd,(struct sockaddr *)&cli_addr, &clilen))<0)
{
perror("Error: could no accept connection");
exit(1);
}
int n = recvfrom(newsockfd, buffer, MAX_LINE,0,(struct sockaddr *) &serv_addr,&clilen);
if(strcmp(buffer, "quit\n")== 0)
{
quit = 0;
break;
}
else
fputs(buffer, stdout);
//get data to be sent
fgets(buffer, MAX_LINE,stdin);
if(strcmp(buffer, "quit\n") == 0) //if quit is entered, terminate conn
{
quit = 0;
int n;
n = sendto(newsockfd, buffer, MAX_LINE,0, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
if (n<0)
error("ERROR: could not send data");
break;
}
//send data
n = sendto(newsockfd, buffer, MAX_LINE, 0, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
if (n<0)
error("ERROR sending data");
}
}

#user58697 is correct as to the proximate cause: last argument to sendto/recvfrom must be a pointer. However, I would add an additional note.
There's no point in using recvfrom/sendto in this program. You have a connected TCP socket; hence there's no reason to provide the sockaddr argument in each call. The addresses won't change, and you already know what they are (i.e. client knows its own address and specifies the address of the sender in the connect; server knows its own address and receives the client's address in the accept).
So once the connection is made, use the simpler send and recv functions instead. This will simplify your code and should simultaneously fix the problem.

You are making some big mistakes with this code, on both sides. Mostly bad socket management and bad buffer management. Try something more like this instead:
//Client side:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define SERVER_PORT 5432
#define MAX_LINE 256
void error(char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char * argv[])
{
struct hostent *hp;
struct sockaddr_in serv_addr;
char *host;
char buf[MAX_LINE];
int sockfd, n;
if (argc != 2)
{
fputs("usage: simplex-talk host\n", stderr);
exit(1);
}
host = argv[1];
hp = gethostbyname(host);
if (!hp)
{
fprintf(stderr, "error: can't find such host: %s\n", host);
exit(1);
}
if (hp->h_addrtype != AF_INET)
{
fprintf(stderr, "error: host does not have an IPv4 address: %s\n", host);
exit(1);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)hp->h_addr, (char *)&serv_addr.sin_addr.s_addr, hp->h_length);
serv_addr.sin_port = htons(SERVER_PORT);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR creating socket");
printf("successfully created socket\n");
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
fputs("ERROR: could not connect\n", stderr);
close(sockfd);
exit(1);
}
printf("successfully connected to server\n");
int quit = 0;
while (quit == 0)
{
fgets(buf, sizeof(buf), stdin);
if (strcmp(buf, "quit\n") == 0)
{
quit = 1;
n = send(sockfd, buf, strlen(buf), 0);
if (n < 0)
fputs("ERROR: couldn't send data to server\n", stderr);
break;
}
n = send(sockfd, buf, strlen(buf), 0);
if (n < 0)
{
fputs("ERROR: couldn't send data to server\n", stderr);
break;
}
//receive data from server
n = recv(sockfd, buf, sizeof(buf)-1, 0);
if (n < 0)
{
fputs("ERROR: couldn't receive from server\n", stderr);
break;
}
if (n == 0)
{
printf("server disconnected\n");
break;
}
buf[n] = 0;
if (strcmp(buf, "quit\n") == 0)
quit = 1;
else
fputs(buf, stdout); //print what is received
}
close(sockfd);
return 0;
}
// Server side:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define MAX_LINE 256
void error(char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, clisockfd, portno, n;
char buffer[MAX_LINE];
struct sockaddr_in serv_addr, cli_addr;
int clilen;
if (argc < 2)
error("ERROR, no port provided");
portno = atoi(argv[1]);
//create a socket
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR creating socket");
//bind address to socket
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR: could not bind socket");
//listen for connection request
if (listen(sockfd, 5) < 0)
error("ERROR: could not listen on socket");
int quit = 0;
while (quit == 0)
{
clilen = sizeof(serv_addr);
clisockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen);
if (clisockfd < 0)
error("ERROR: could not accept connection");
while (quit == 0)
{
n = recv(clisockfd, buffer, sizeof(buffer)-1, 0);
if (n < 0)
{
fputs("ERROR: couldn't receive from client\n", stderr);
break;
}
if (n == 0)
{
printf("client disconnected\n");
break;
}
buffer[n] = 0;
if (strcmp(buffer, "quit\n") == 0)
{
quit = 1;
break;
}
fputs(buffer, stdout);
//get data to be sent
fgets(buffer, sizeof(buffer), stdin);
if (strcmp(buffer, "quit\n") == 0) //if quit is entered, terminate conn
{
quit = 1;
n = send(clisockfd, buffer, strlen(buffer), 0);
if (n < 0)
fputs("ERROR: could not send data to client\n", stderr);
break;
}
//send data
n = send(clisockfd, buffer, strlen(buffer)-1, 0);
if (n < 0)
{
fputs("ERROR sending data to client\n", stderr);
break;
}
}
close(clisockfd);
}
close(sockfd);
return 0;
}
Now, with that said, do note that TCP is a streaming transport. There is no 1-to-1 relationship between send() and recv() and no concept of messages, like this code assumes. The sender could send a message like "hello joe\n" and the receiver could read like "hello" " joe" "\n", depending on how TCP decides to break of the data during transmission. You really need to take that into account. Read raw bytes and append them to the end of a buffer. Check the buffer for a message terminator (in this case, \n). If found, process that complete message and remove it from the buffer. Repeat until there are no more terminators found in the buffer. Leaving unprocessed data in the buffer so it can be completed by subsequent reads.
I'll leave this as an exercise for you.

Related

Server delay on system command in C

I have two programs, one acting as a server and one acting as a client. They are supposed to act like you are connecting to remote system using ssh. The client sends a command and the server executes the command and prints the output to the server. Although my code does exactly that, there is a delay on the output after the first command. For example if the client sents date, the server will return the date. If the client sends date again it will print message was received but not the output. On the third input from client, the second date will be executed and print on the client Here is the message:date and so on. Any ideas would be really apreciated.
Server:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <fcntl.h>
#define MAX_PINS 1
void error(const char *msg){
perror(msg);
exit(1);
}
void exec_comm(int sock,int nerror,char buff[]){
dup2(sock,1);
dup2(nerror,2);
if(system(buff)==-1){
printf("command not found\n");
}
}
int main(int argc, char *argv[]){
int sockfd, newsockfd, portno, pid;
socklen_t clilen;
char buffer[256];
char* comm[20],*cbuff;
struct sockaddr_in serv_addr, cli_addr;
int n,i,done=0,correct=0;
char str[INET_ADDRSTRLEN];
char* args,*pins[MAX_PINS]={"1234"},pin[10];
FILE* fd;
int nerror;
if (argc < 2){
fprintf(stderr, "No port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
memset((char *) &serv_addr, 0, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd,(struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd, 5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR on accept");
if (inet_ntop(AF_INET, &cli_addr.sin_addr, str, INET_ADDRSTRLEN) == NULL) {
fprintf(stderr, "Could not convert byte to address\n");
exit(1);
}
fprintf(stdout, "The client address is :%s\n", str);
while(1){
bzero(buffer, 256);
n = read(newsockfd, buffer, 255);
sscanf(buffer,"%s\n",buffer);
printf("The message that was read was:\t%s\n",buffer);
if (n < 0) error("ERROR reading from socket");
fprintf(fd,"%s\n",buffer);
if(strcmp(buffer,"exit\n")==0||strcmp(buffer,"exit")==0){
printf("Exiting...\n");
done=1;
break;
}
exec_comm(newsockfd,nerror,buffer);
printf("Here is the message: %s\n", buffer);
n = write(newsockfd, "message received", 17);
if (n < 0) error("ERROR writing to socket");
}
fclose(fd);
close(newsockfd);
close(sockfd);
return 0;
}
Client:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
void error(const char *msg){
perror(msg);
exit(0);
}
int main(int argc, char *argv[]){
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
if (argc < 3){
fprintf(stderr, "usage %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]);
if (server == NULL){
fprintf(stderr, "ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
n = write(sockfd, stdin, sizeof(int));
if (n < 0)
error("ERROR writing to socket");
do{
printf("Please enter the message: ");
bzero(buffer, 256);
fgets(buffer, 255, stdin);
if(strcmp(buffer,"exit\n")==0||strcmp(buffer,"exit")==0){
printf("Exiting...\n");
n = write(sockfd, buffer, strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
close(sockfd);
break;
}
n = write(sockfd, buffer, strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
bzero(buffer, 256);
n = read(sockfd, buffer, 255);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n", buffer);
}while(1);
return 0;
}
n = write(sockfd, buffer, strlen(buffer));
That's your problem right here. Calls to write do not result in individual distinguishable messages, one message per call. They result in a single homogenous stream (that's the "stream" in SOCK_STREAM) of bytes with no delimiters.
You have newlines that separate commands, which is nice and all, but read has no idea about newlines. It will just wait until the buffer is full, or enough time has passed, or whatever. You have no control over it.
You basically have 2 ways to fix this.
Read character by character (pass the length of 1) and stop as soon as you see a newline. Accumulate the characters in a buffer, then execute it.
Send the length of each message before the message itself, in a fixed-length record, so that the server can safely read the length and then use it to read the message itself.

Server accepts messages but not commands in C

I currently trying to create a program that you can connect from anywhere via the internet using sockets. I obviously want to execute commands and display the output to the client but also want to return anything that the client typed and if it was received, display message reveived. My problem is that even though it displays what was send, it doesn't execute commands. I have tryied to use gdb with break lines inide the while loop but they don't work as if the while loop is never executed.
Server:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno, pid;
socklen_t clilen;
char buffer[256];
char* comm[20],*cbuff;
struct sockaddr_in serv_addr, cli_addr;
int n,i;
char str[INET_ADDRSTRLEN];
char* args;
if (argc < 2)
{
fprintf(stderr, "No port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
memset((char *) &serv_addr, 0, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd,(struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR on binding");
for(;;){
listen(sockfd, 5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR on accept");
if (inet_ntop(AF_INET, &cli_addr.sin_addr, str, INET_ADDRSTRLEN) == NULL) {
fprintf(stderr, "Could not convert byte to address\n");
exit(1);
}
fprintf(stdout, "The client address is :%s\n", str);
while(1){
bzero(buffer, 256);
n = read(newsockfd, buffer, 255);
if (n < 0) error("ERROR reading from socket");
if(buffer=="exit"){
printf("Exiting...\n");
break;
}
cbuff=strtok(buffer," ");
i=0;
while(cbuff!=NULL){
cbuff=strtok(NULL," ");
comm[i]=cbuff;
i++;
}
if ((pid=fork())==-1){
perror("fork");
}
if(pid!=0){
wait(NULL);
}
else{
dup2(newsockfd,1);
printf("executing...\n");
execvp(comm[0],comm);
perror("execvp");
exit(EXIT_FAILURE);
}
printf("Here is the message: %s\n", buffer);
n = write(newsockfd, "message received", 17);
if (n < 0) error("ERROR writing to socket");
}
break;
}
close(newsockfd);
close(sockfd);
return 0;
}
Client:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
void error(const char *msg){
perror(msg);
exit(0);
}
int main(int argc, char *argv[]){
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
if (argc < 3){
fprintf(stderr, "usage %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]);
if (server == NULL){
fprintf(stderr, "ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
do{
printf("Please enter the message: ");
bzero(buffer, 256);
fgets(buffer, 255, stdin);
if(buffer=="exit"){
printf("Exiting...\n");
break;
}
n = write(sockfd, buffer, strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
bzero(buffer, 256);
n = read(sockfd, buffer, 255);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n", buffer);
}while(1);
return 0;
}

Issue using c sockets with threads to read from and write to the socket

I want to write a TCP server-client chat, but when I start the two threads for reading from and writing to a socket at both sides, I think they block each other out. Can anyone help me with this?
Server Code:
/* A simple server in the internet domain using TCP the port number is passed as an argument */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
struct server_args_runner{
char buffer [256];
int newsockfd;
pthread_t tid;
pthread_attr_t attr;
//read/write attribute (read == 0 and write == 1)
int rw;
};
void error(char *msg){
perror(msg);
exit(1);
}
void* server_runner_fun(void* args){
// this is the chat part!
// get args:
int n;
struct server_args_runner *sar = (struct server_args_runner*) args;
if(sar->rw == 0){
printf("server thread trys to read from socket...\n");
//read-part
while(1){
bzero(sar->buffer, 256);
n = read(sar->newsockfd, sar->buffer, 255);
if (n < 0){
error("ERROR reading from socket");
}
}
printf("%s\n", sar->buffer);
} else {
printf("server thread trys to write to socket...\n");
//write-part
while(1){
bzero(sar->buffer, 256);
fgets(sar->buffer, 255, stdin);
n = write(sar->newsockfd, sar->buffer, strlen((char *) &(sar->buffer)));
if (n < 0){
error("ERROR writing to socket");
}
}
}
}
int main(int argc, char *argv[]){
//fd = filedescriptor
int sockfd, portno, clilen;
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2){
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
//socket(...) returns a descriptor
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1){
error("ERROR opening socket");
}
printf("Socket created successfully.\n");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
//htons(..) converts the short from hostbyteorder to networkbyteorder
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) == -1){
error("ERROR on binding");
}
printf("binding successfull on port %d\n", portno);
listen(sockfd, 2);
clilen = sizeof(cli_addr);
printf("server is listening ...\n");
struct server_args_runner server_write_t, server_read_t;
server_write_t.newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr, &clilen);
printf("server accepted connection to client.\n");
if (server_write_t.newsockfd < 0){
error("ERROR on accept");
}
//initializing both server_threads
pthread_attr_init(&server_write_t.attr);
pthread_attr_init(&server_read_t.attr);
server_write_t.rw = 1;
server_read_t.rw = 0;
bcopy(&server_write_t.newsockfd, &server_read_t.newsockfd, sizeof(server_write_t.newsockfd));
pthread_create(&server_write_t.tid, &server_write_t.attr, server_runner_fun, &server_write_t);
pthread_create(&server_read_t.tid, &server_read_t.attr, server_runner_fun, &server_read_t);
pthread_join(server_write_t.tid, NULL);
pthread_join(server_read_t.tid, NULL);
return 0;
}
Client code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <pthread.h>
struct client_args_runner{
char buffer [256];
int sockfd;
pthread_t tid;
pthread_attr_t attr;
//read/write attribute (read == 0 and write == 1)
int rw;
};
void error(char *msg){
perror(msg);
exit(0);
}
void* client_runner_fun(void* args){
// this is the chat part!
// get args:
int n;
struct client_args_runner *car = (struct client_args_runner*) args;
if(car->rw == 0){
printf("client thread trys to read from socket...\n");
//read-part
while(1){
bzero(car->buffer, 256);
n = read(car->sockfd, car->buffer, 255);
if (n < 0){
error("ERROR reading from socket");
}
}
printf("%s\n", car->buffer);
} else {
printf("client thread trys to write to socket...\n");
//write-part
while(1){
bzero(car->buffer, 256);
fgets(car->buffer, 255, stdin);
n = write(car->sockfd, car->buffer, strlen((char *) &(car->buffer)));
if (n < 0){
error("ERROR writing to socket");
}
}
}
}
int main(int argc, char *argv[]){
int portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
if (argc < 3){
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
struct client_args_runner client_write_t, client_read_t;
client_write_t.sockfd = socket(AF_INET, SOCK_STREAM, 0);
bcopy(&client_write_t.sockfd, &client_read_t.sockfd,
sizeof(client_write_t.sockfd));
if (client_write_t.sockfd == -1){
error("ERROR on creating socket_file_descriptor");
}
printf("socket created successfully.\n");
server = gethostbyname(argv[1]);
printf("hostname is valid.\n");
if(server == NULL){
fprintf(stderr, "Error, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *) server->h_addr, (char *) &serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(portno);
printf("before connecting to client..\n");
if (connect(client_write_t.sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) == -1){
error("ERROR connecting");
}
printf("client connected successfully to server.\n");
//initializing both client_threads
pthread_attr_init(&client_write_t.attr);
pthread_attr_init(&client_read_t.attr);
client_write_t.rw = 1;
client_read_t.rw = 0;
pthread_create(&client_write_t.tid, &client_write_t.attr, client_runner_fun, &client_write_t);
pthread_create(&client_read_t.tid, &client_read_t.attr, client_runner_fun, &client_read_t);
pthread_join(client_write_t.tid, NULL);
pthread_join(client_read_t.tid, NULL);
return 0;
}
Your printfs in both the client and server readers are outside the while(1) loops, so your client and server are communicating fine, you just aren't printing anything you read from the sockets.

Client hangs when tries to read back from server tcp

i am trying to create a simple tcp server-client. My programm works fine if client sends data to server but when server tries to answer back the whole connection hangs. I am using write()/read() functions .
Server code :
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
#include <stdbool.h>
#define SIZE 700000000
///////////////////////////////////////////////////////////////////////////
int main( int argc, char *argv[] ) {
int sockfd, newsockfd, portno, clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
/* First call to socket() function */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("ERROR opening socket");
exit(1);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = 5001;
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
perror("ERROR on binding");
exit(1);
}
listen(sockfd, 10);
clilen = sizeof(cli_addr);
/* Accept actual connection from the client */
newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen);
if (newsockfd < 0) {
perror("ERROR on accept");
exit(1);
}
bzero(buffer, 255);
int readbyte = 0;
do {
readbyte = read(newsockfd, buffer, 1024);
if (readbyte < 0)
{
perror("ERROR on reading socket!");
break;
}
if (readbyte > 0)
{
//printf("Here is the message: %s\n",buffer);
}
} while (readbyte > 0); /* until EOF */
int writen = write(newsockfd, "I received your message", strlen("I received your message") + 1);
if (writen<0){
perror("Error");
}
//debug();
return 0;
}
Client code:
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
//////////////////////////////////////////////////////////////////
int main(int argc, char *argv[]) {
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
int mode;
char *code;
char buffer[256];
char *uptr = buffer;
int i;
if (argc < 3) {
fprintf(stderr, "Use: %s [hostname] [port] [args]\n", argv[1]);
exit(0);
}
portno = atoi(argv[2]);
/* Create a socket point */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("ERROR opening socket");
exit(1);
}
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr, "ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(portno);
int sock_et = connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr);
/* Now connect to the server */
if (sock_et < 0) {
perror("ERROR connecting");
exit(1);
}
/* some code... */
while (len > 0) {
int writen = write(sockfd, buf, len + 1);
if (writen < 0)
{
printf("Error writting to socket!\n");
break;
}
len -= writen;
buf += writen; /* tricky pointer arythmetic */
}
printf("Finished writing to server\n");
bzero(buffer, 256);
int readbyte;
do {
readbyte = read(sock_et, buffer, 1024);
if (readbyte < 0)
{
perror("ERROR on reading socket!");
break;
}
if (readbyte > 0)
{
//printf("Here is the message: %s\n",buffer);
}
} while (readbyte > 0); /* until EOF */
printf("%s\n",buffer );
close(sockfd);
return 0;
}
Any help would be appreciated! Thanks!
Your client code doesn't compile
You are never going to get a 0 (EOF) from read while the socket is open (in either the client or server) -- so just add a break after a successful read for now.
You are not closing the socket in the server
In the client, you need to read from sockfd, not sock_et
There are probably other issues. It looks like you are trying to use client.c/server.c from here: http://www.linuxhowtos.org/C_C++/socket.htm
If I use those files, it works fine. So start over from them and apply your changes more carefully.

c - client server communication via socket in infinite loop

I have the following code below for a client page and a server page, for which I want to send five messages from the client side to the server side (for this initial test, anyway). The code works fine if I don't put it in a loop, but then I can only send one message before both the client and server close. When I put the code in a loop, it seems to get stuck in some sort of deadlock. The results I get are below followed by the code. I've tried various changes and done extensive research but just can't make it work. Thanks in advance for any solutions offered.
Server side results
./server 5000
Here is the message: test
Client side results
./client localhost 5000
Please enter the message: test
I got your message
Please enter the message: another test
Please enter the message: test again
Please enter the message: test yet again
// The server stops acknowledging receipt of the message and I have to keep resetting both client and server
server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno, clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2) {
printf("Need at least two arguments\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
printf("ERROR opening socket\n");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
printf("ERROR on binding\n");
listen(sockfd,atoi(argv[1]));
clilen = sizeof(cli_addr);
while ((newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen)) >= 0) {
if (newsockfd < 0)
printf("ERROR on accept\n");
bzero(buffer,256);
n = read(newsockfd,buffer,255);
if (n < 0) printf("ERROR reading from socket\n");
printf("Here is the message: %s\n",buffer);
n = write(newsockfd,"I got your message\n",18);
if (n < 0) printf("ERROR writing to socket\ns");
}
close(sockfd);
return 0;
}
client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
int main(int argc, char *argv[]) {
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
if (argc < 3) {
printf("Not enough arguments\n");
exit(0);
}
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
printf("Error opening socket\n");
server = gethostbyname(argv[1]);
if (server == NULL) {
printf("Error: no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
printf("Error connecting\n");
int i = 0;
while (i < 5) {
printf("Please enter the message: ");
bzero(buffer, 256);
fgets(buffer, 255, stdin);
n = write(sockfd, buffer, strlen(buffer));
if (n < 0)
printf("Error writing to socket");
bzero(buffer, 256);
n = read(sockfd, buffer, 255);
if (n < 0)
printf("Error reading from socket");
printf("%s\n", buffer);
i++;
}
close(sockfd);
return 0;
}
You need to restructure your code to deal with the one connection you have before accepting another one. This is terrible code but is the basic template for what you want to do. Even so you can't deal with more than one connection at a time with this. You either have to multiplex or thread. Also, always read/write in a loop because you are not guaranteed to get a full request filled on any one call. Learn about and use perror or brothers.
void do_stuff(int sock)
{
for (int i = 0; i < 5; ++i)
{
bzero(buffer, 256);
n = read(newsockfd, buffer, 255);
if (n < 0)
printf("ERROR reading from socket\n");
printf("Here is the message: %s\n", buffer);
n = write(newsockfd, "I got your message\n", 18);
if (n < 0)
printf("ERROR writing to socket\ns");
}
}
while ((newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen)) >= 0)
{
if (newsockfd < 0)
printf("ERROR on accept\n");
do_stuff(newsockfd);
close(newsockfd);
}
I know its too late. But for someone who might have the same doubt I am trying to answer this.
Answer
How about changing the server program to this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno, clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2) {
printf("Need at least two arguments\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
printf("ERROR opening socket\n");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
printf("ERROR on binding\n");
listen(sockfd,atoi(argv[1]));
clilen = sizeof(cli_addr);
while ((newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen)) >= 0) {
if (newsockfd < 0)
printf("ERROR on accept\n");
bzero(buffer,256);
while(true)
{
n = read(newsockfd,buffer,255);
if (n < 0)
{
printf("ERROR reading from socket\n");
break;
}
printf("Here is the message: %s\n",buffer);
n = write(newsockfd,"I got your message\n",18);
if (n < 0)
{
printf("ERROR writing to socket\ns");
break;
}
}
close(newsockfd);
}
close(sockfd);
return 0;
}
This is the changed part. I changed the code slightly such that the connection will close if any write or read error occurs.
while ((newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen)) >= 0) {
if (newsockfd < 0)
printf("ERROR on accept\n");
bzero(buffer,256);
while(true)
{
n = read(newsockfd,buffer,255);
if (n < 0)
{
printf("ERROR reading from socket\n");
break;
}
printf("Here is the message: %s\n",buffer);
n = write(newsockfd,"I got your message\n",18);
if (n < 0)
{
printf("ERROR writing to socket\ns");
break;
}
}
close(newsockfd);
}

Resources