Reputation: 61
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");
}
}
Upvotes: 1
Views: 278
Reputation: 595329
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.
Upvotes: 1
Reputation: 12337
@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.
Upvotes: 1