Sending multiple messages over a TCP port - c

I have a program that creates a socket (server and client program) and sends a message via a TCP port using that socket. My question is, how can I exchange multiple messages?
Every time I send a message the port gets closed and I need to use another port to send another message.
For example, I have to send 2 numbers from the client to the server and the server needs to reply back the total sum of the numbers I send. How would I achieve sending undefined number or even 2 numbers over the SAME port?
Here are the codes (pretty much standard stuff):
Server:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
char* Itoa(int value, char* str, int radix)
{
static char dig[] =
"0123456789"
"abcdefghijklmnopqrstuvwxyz";
int n = 0, neg = 0;
unsigned int v;
char* p, *q;
char c;
if (radix == 10 && value < 0) {
value = -value;
neg = 1;
}
v = value;
do {
str[n++] = dig[v%radix];
v /= radix;
} while (v);
if (neg)
str[n++] = '-';
str[n] = '\0';
for (p = str, q = p + (n-1); p < q; ++p, --q)
c = *p, *p = *q, *q = c;
return str;
}
void error (const char *msg)
{
perror (msg);
exit (1);
}
int main (int argc, char *argv[])
{
if (argc < 2)
{
fprintf (stderr, "ERROR, no port provided\n");
exit (1);
}
//nova varijabla za sumiranje primljenih brojeva
int suma=0;
int sockfd, newsockfd, portno,i;
socklen_t clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
for (i=0;i<2;i++)
{
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]);
portno+=i;
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");
//test za ispis otvorenog porta
printf("Uspjesno otvoren localhost na portu %d\n", portno);
listen (sockfd, 5);
clilen = sizeof (cli_addr);
newsockfd = accept (sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0) error ("ERROR on accept");
memset (buffer, 0, 256);
n = read (newsockfd, buffer, 255);
if (n < 0) error ("ERROR reading from socket");
printf ("%d. proslan broj: %s\n", i+1, buffer);
//print
suma=suma+atoi(buffer);
//radi!! printf("suma je %d\n", suma);
//od klijenta: n = write (sockfd, buffer, strlen (buffer));
//char * itoa ( int value, char * str, int base );
Itoa(suma, buffer, 10);
n = write (newsockfd, buffer, strlen(buffer));
if (n < 0) error ("ERROR writing to socket");
close (newsockfd);
close (sockfd);
}
return 0;
}
Client:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
void error (const char *msg)
{
perror (msg);
exit (1);
}
int
main (int argc, char *argv[])
{
if (argc < 3)
{
fprintf (stderr, "usage %s hostname port\n", argv[0]);
exit (1);
}
int sockfd, portno, n,i;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
for (i=0;i<2;i++)
{
portno = atoi (argv[2]);
sockfd = socket (AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error ("Ne mogu otvoriti socket!");
server = gethostbyname (argv[1]);
if (server == NULL)
{
fprintf (stderr, "Greska, ne postoji!\n");
exit (1);
}
memset ((char *) &serv_addr, 0, sizeof (serv_addr));
serv_addr.sin_family = AF_INET;
bcopy ((char *) server->h_addr,
(char *) &serv_addr.sin_addr.s_addr,
server->h_length);
portno+=i;
serv_addr.sin_port = htons (portno);
if (connect (sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0)
error ("ERROR connecting");
printf ("%d. broj za slanje: ", i+1);
memset (buffer, 0, 256);
fgets (buffer, 255, stdin);
n = write (sockfd, buffer, strlen (buffer));
if (n < 0)
error ("ERROR writing to socket");
memset (buffer, 0, 256);
n = read (sockfd, buffer, 255);
if (n < 0)
error ("ERROR reading from socket");
if (i==1) printf ("Suma iznosi: %s\n", buffer);
close (sockfd);
}
return 0;
}
So, for example, I run the code and get this for the server side:
j#PC ~/Desktop/Mreze/Lab1/rijeseno $ ./server2 5000
Uspjesno otvoren localhost na portu 5000
1. proslan broj: 45
Uspjesno otvoren localhost na portu 5001
2. proslan broj: 56
j#PC ~/Desktop/Mreze/Lab1/rijeseno $
And on the client side:
j#PC ~/Desktop/Mreze/Lab1/rijeseno $ ./client2 localhost 5000
1. broj za slanje: 45
2. broj za slanje: 56
Suma iznosi: 101
I've tried putting a while loop so it loops the part with sending but without success. Please explain to me where should I even put it so it works. Thank you!

Here is a problem:
n = read (newsockfd, buffer, 255);
What you do, is you perform read once, and the data might not be fully available. The fact is, you need to read data, as long as you received the data completely, or detected EOF condition (-1 return value).
Generally you need to write more reliable code for receiving part, as it is not guaranteed on stream protocol that your message boundaries are kept in any form.
Here is a (very unoptimal, yet simple) code for reading data:
int readLine(int fd, char data[])
{
size_t len = 0;
while (len < maxlen)
{
char c;
int ret = read(fd, &c, 1);
if (ret < 0)
{
data[len] = 0;
return len; // EOF reached
}
if (c == '\n')
{
data[len] = 0;
return len; // EOF reached
}
data[len++] = c;
}
}
And usage example:
char buffer[256];
int num1, num2;
readLine(newsockfd, buffer);
num1 = atoi(buffer);
readLine(newsockfd, buffer);
num2 = atoi(buffer);

First Put your connection() function before and close() after for loop. Just for an idea
connect (sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)
for (i=0;i<n;i++){
// do you introspection with server
// actually send number to server
}
// Code to read result: SUM from server
close (sockfd);

Related

Behavior of strcmp appears to be weird during inter-process communication using sockets

I wrote a program in which I used to scan a string and a keyword from the user and return the number of occurrences of that keyword in the string. I used strcmp function after splitting the input string on white spaces and it worked fine.
Now, I am trying to do the same work using IPC with sockets where the client inputs the strings and keywords, and the server does the counting work. But in this case, I am not getting the same results for the same input. I looked at the return values of strcmp and found that it is returning non-zero values even when the input strings appear same to me.
What could be the cause & how can I resolve it?
Here is the code for server.
Reference: http://www.linuxhowtos.org/C_C++/socket.htm
/* 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 <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
//
char * input;
char * str;
char * word;
int i, wordLen, strLen;
char terminator = ';';
char * pch;
char * new;
int temp, count = 0;
//
int sockfd, newsockfd, portno;
socklen_t clilen;
char buffer[36];
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
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)
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");
bzero(buffer,36);
n = read(newsockfd,buffer,35);
if (n < 0) error("ERROR reading from socket");
//
input = (char *) malloc(36);
strcpy(input, buffer);
word = strchr(input, terminator);
temp = (strlen(input) - strlen(word));
str = (char *) malloc(temp);
//strlcpy(str, input, temp);
*str = '\0';
strncat(str, input, temp);
word++;
wordLen = strlen(word);
new = (char *) malloc(temp);
//strlcpy(str, input, temp);
strcpy(new, str);
strLen = strlen(str);
// if (word != NULL && str != NULL) printf("%s%d\n%s%d\n", word, wordLen, new, strLen);
pch = strtok (str," ,.-");
while (pch != NULL)
{
printf ("%s\n",pch);
if(strcmp(pch, word) == 0) count++;
else printf("%s%s%d\n", pch, word, strcmp(pch, word));
pch = strtok (NULL, " ,.-");
printf("(%s)\n",word );
}
//
printf("Here is the output: %d\n",count);
//n = write(newsockfd,"Result: %d\n",count, 18);
if (n < 0) error("ERROR writing to socket");
free(str);
free(input);
free(new);
close(newsockfd);
close(sockfd);
return 0;
}
The only thing weird here is that you are assuming that every read() results in an null-terminated buffer. It returns a read count. Use it.

C multisocket program not working

I am trying to create a simple client/server socket-based program. It's just a basic "Guess the number" game, where the server comes up with a number and then the client(s) try to guess the number. The problem is that I am having problems with the programs working as intended.
The problem is such: When I launch up the server program and it generates the random number, I try loading up the client programs, but after one input, they stop working. It stops after outputting this:
Guess: 42
Buffer to be processed : <42
>
integerGuess : <42>
String Guess : <42\n>
Buffer to send : <42\n>
Here's the server.c file code:
#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 <time.h> /* time for randomizer*/
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno, n;
socklen_t clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int GuessedInteger, integerRandom, serverFlagCorrect;
char charGuess[4], answerServer[1];
char* delimiter = "\\n";
/** initialization of variables **/
serverFlagCorrect = 0;
/** generate random integer from 1 to 100 **/
srand (time(NULL));
integerRandom = (rand() % 100) + 1;
printf("This is the random integer : %d \n", integerRandom);
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
// Creates the socket socket() --> endpoints of sockets
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
// Creates the socket socket() --> endpoints of sockets
// assign unique new address
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)
error("ERROR on binding");
// assign unique new address
// wait for a connection
listen(sockfd,5);
// wait for a connection
// accepts the connection
clilen = sizeof(cli_addr);
while (1) {
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR on accept");
n = fork();
if (n < 0)
error("ERROR on fork");
if (n == 0) {
close(sockfd);
dostuff(newsockfd);
exit(0);
}
else close(newsockfd);
} /* end of while */
close(sockfd);
return 0; /* we never get here */
}
void dostuff (int sock) {
int GuessedInteger, integerRandom, serverFlagCorrect;
char charGuess[4], answerServer[1];
char* delimiter = "\\n";
int sockfd, newsockfd, portno, n;
socklen_t clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
while (serverFlagCorrect != 1)
{
// reads the data being received
bzero(buffer,256);
n = read(newsockfd,buffer,255);
if (n < 0) error("ERROR reading from socket");
// reads the data being received
printf("Buffer from client: <%s>\n", buffer);
memcpy(charGuess, buffer, sizeof(charGuess));
printf("Message from client in charGuess: <%s>\n", charGuess);
/* Put if statement here for error out if no \n at the end */
int len = strlen(charGuess);
const char *last_two = &charGuess[len-2];
printf("Last two characters of charGuess: <%s>\n", last_two);
if (strncmp ( last_two, delimiter, 2) )
error (" ERROR Wrong protocol received");
/** turn string to int for comparison **/
GuessedInteger = atoi(charGuess);
printf("Guessed Integer : %d \n", GuessedInteger);
/** Server response for comparison**/
if (GuessedInteger > integerRandom)
memcpy(&answerServer, "Lower", sizeof(answerServer));
else if (GuessedInteger < integerRandom)
memcpy(&answerServer, "Higher", sizeof(answerServer));
else if (GuessedInteger == integerRandom)
{
serverFlagCorrect = 1;
memcpy(&answerServer, "Correct", sizeof(answerServer));
}
printf("Value of answerServer: %c\n", *answerServer);
/** Server response for comparison**/
// sends the answer
n = write(newsockfd, answerServer, 1);
if (newsockfd < 0)
error("ERROR on accept");
// sends the answer
// closes what was sent
}
close(newsockfd);
}
Here's the client.c code:
#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[1024];
int integerGuess, clientFlagCorrect;
int numberOfTries;
char charGuess[1024], answerServer[1];
char* delimiter = "\\n";
if (argc < 3) {
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
// Creates the socket socket() --> endpoints of sockets
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
// Creates the socket socket() --> endpoints of sockets
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
// connects to the service in connect()
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");
// connects to the service
/** variables **/
clientFlagCorrect = 0;
numberOfTries = 0;
while (clientFlagCorrect != 1)
{
numberOfTries = numberOfTries + 1;
/** initializing vars **/
integerGuess = 0;
memset(charGuess, 0, sizeof(charGuess));
// ask for the number
printf("Guess: ");
bzero(buffer,sizeof(buffer));
fgets(buffer,sizeof(buffer)-1,stdin);
printf("Buffer to process is : <%s>\n", buffer);
// ask to see if the number is guessed
/** string and delimeter **/
integerGuess = atoi(buffer);
printf("int Guess : <%d> \n", integerGuess);
sprintf( charGuess, "%d", integerGuess);
strcat( charGuess, delimiter);
printf("String Guess : <%s> \n", charGuess);
memset(buffer,0,sizeof(buffer));
memcpy(buffer, charGuess, sizeof(charGuess));
printf("Buffer to be sent is: : <%s>\n",buffer);
/** process the integer to string and add a delimiter **/
// send the string that was processed
n = write(sockfd,buffer,strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
// send the string that was processed
// reads the data being received
bzero(buffer,256);
n = read(sockfd,buffer,255);
if (n < 0)
error("ERROR reading from socket");
// reads the data being received
printf("Buffer received : <%s>\n",buffer);
memcpy(&answerServer, buffer, sizeof(answerServer));
printf ("Value of answerServer : <%c> \n", *answerServer);
/** Client response **/
if (strncmp ( & answerServer[0],"Lower",sizeof(answerServer)) == 0)
printf("The number is lower \n");
else if (strncmp ( & answerServer[0],"Higher",sizeof(answerServer)) == 0)
printf("The number is higher \n");
else if (strncmp ( & answerServer[0],"Correct",sizeof(answerServer)) == 0)
{
printf("Your guess is correct! \n");
clientFlagCorrect = 1;
}
else
error("ERROR Wrong message received");
}
printf ("It took you this many tries: %d \n", numberOfTries);
printf("%s\n",buffer);
close(sockfd);
return 0;
}
Any help would be greatly appreciated.
EDIT: After some extra work and "Debugging" (consisting mostly of me adding a load of printf's at various points) I am 90% convinced the problem is on the server side. I added printf's before and after this line:
printf("This is the random integer : %d \n", integerRandom);
And found that while the printf immediately before the line prints out fine, placing one right below it only prints it if prints out the "No port detected" error. Any further printf's don't trigger at all, which means that the program doesn't even reach the main loop that does the program.
As for the client file, it reached the line:
printf("Buffer to be sent is: : <%s>\n",buffer);
And stops (Once again via printf's). Why, I honestly have no clue. Which means there's a problem somewhere around those points, but where, I honestly have no clue.

How to convert char[ ] to char *?

I'm wondering how to convert a char[] array to a char *
For example, in my code I am trying to access a web server using a hostname like "example.com"
Using my code, if I set a char * to "example.com" like below, it works perfectly.
char *host = "example.com";
But, what I really want to do is be able to read from a client program using a socket, write to a char[] array, and use the data obtained from that as the hostname.
For example,
char buffer[4096], hostname[4096];
bzero(buffer, 4096);
n = read(newsockfd, buffer, 4095);
strcpy(hostname, buffer);
printf("Here is the hostname: %s\n", &hostname[0]);
int sockwb, wbport, x;
struct sockaddr_in webser_addr;
struct hostent *wbhost;
char webbuf[4096];//sending to webserver
wbport = 80;//port used to access web server
sockwb = socket(AF_INET, SOCK_STREAM, 0);
wbhost = gethostbyname(hostname);
when my code gets to the last line, it just sits there, so I'm thinking its a typing problem, since when I do this:
char *host = "example.com";
...
wbhost = gethostbyname(host);
It works, and is able to get the data from the web and send it properly to my client program.
Any ideas are appreciated.
In the client program I use fgets() to read into a char[] from stdin then use write() to write to the socket for the server program to read. I had tried to use strcat() to add '\0' to the end of the char[] before writing to the socket but that didn't seem to do anything
Full Code: (Please ignore the comments, just trying different things for now)
client
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int sockfd, portnum, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[4096];
if(argc < 3)
{
fprintf(stderr, "usage %s hostname port\n", argv[0]);
exit(1);
}
portnum = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
{
perror("ERROR opening Socket");
exit(1);
}
server = gethostbyname(argv[1]);
if(sockfd == NULL)
{
fprintf(stderr, "ERROR, no such host\n");
exit(1);
}
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(portnum);
if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
fprintf(stderr, "ERROR, on connecting");
exit(1);
}
printf("Please enter the Host name: ");
bzero(buffer, 4096);
fgets(buffer, 4095, stdin);
//strcat(buffer, "\0");
n = write(sockfd, buffer, strlen(buffer));
if(n < 0)
{
printf("Error writing to socket");
exit(1);
}
bzero(buffer, 4096);
n = read(sockfd,buffer, 4095);
if(n < 0)
{
printf("ERROR reading from socket");
exit(1);
}
printf("%s\n", buffer);
return 0;
}
server
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <netdb.h>
#include <string.h>
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portnum, clilen;
char buffer[4096], hostname[4096];
pid_t p_id;
struct sockaddr_in serv_addr, cli_addr;
int n, pid, hostname_len;
//char *host;
char *host = "example.com";
if(argc < 2)
{
fprintf(stderr, "ERROR, NO PORT PROVIDED!\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);//socket is made
if(sockfd < 0)
{
fprintf(stderr, "ERROR opening socket!!");
exit(1);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
portnum = atoi(argv[1]);//port num
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(portnum);
if(bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
{
fprintf(stderr, "ERROR on binding");
exit(1);
}
if( listen(sockfd, 5) < 0)
{
printf("ERROR ON LISTEN");
exit(1);
}
// accept
clilen = sizeof(cli_addr);
do{
newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen);
if(newsockfd < 0)
{
fprintf(stderr, "ERROR on accept\n");
exit(1);
}
pid = fork();
if(pid == 0)
{
bzero(buffer, 4096);
n = read(newsockfd, buffer, 4095);
if(n < 0)
{//message from client
fprintf(stderr, "ERROR Reading from socket\n");
exit(1);
}
strcpy(hostname, buffer);
printf("Here is the hostname: %s\n", &hostname[0]);
//variables used for acsessing webserver?
int sockwb, wbport, x;
struct sockaddr_in webser_addr;
struct hostent *wbhost;
char webbuf[4096];//sending to webserver
wbport = 80;//port used to access web server
sockwb = socket(AF_INET, SOCK_STREAM, 0);
if(sockwb < 0)
{
printf("Error opeing websocket\n");
exit(1);
}
// hostname_len = sizeof(hostname) / sizeof(hostname[0]);
// printf("%d\n", hostname_len);
// memcpy(host, hostname, hostname_len);
// host[hostname_len] = '\0';
printf("%s\n", host);
// hostname[hostname_len] = '\0';
// host = &hostname[0];
//wbhost = gethostbyname(hostname);
wbhost = gethostbyname(host);
//printf("%s", wbhost->h_name);
printf("here2\n");
/*if(wbhost == NULL)
{
printf("NO SUCH web HOST\n");
exit(1);
}
*/
bzero((char*) &webser_addr, sizeof(webser_addr));
webser_addr.sin_family = AF_INET;
bcopy((char *)wbhost->h_addr, (char *)&webser_addr.sin_addr.s_addr, wbhost->h_length);
webser_addr.sin_port = htons(wbport);
// printf("here3\n");
if(connect(sockwb, (struct sockaddr *) &webser_addr,sizeof(webser_addr)) < 0)
{
printf("Error on web connecting\n");
exit(1);
}
bzero(webbuf, 4096);
strcpy(webbuf, "GET / HTTP/1.0\r\nHost: ");
// strcat(webbuf, hostname);
strcat(webbuf, host);
strcat(webbuf, "\r\nConnection: close\r\n\r\n");
// const char * request = "GET / HTTP/1.0\r\nHost: example.com\r\nConnection: close\r\n\r\n";
// printf("%s\n", request);
// x = write(sockwb, request, strlen(request));
printf("%s\n", webbuf);
x = write(sockwb, webbuf, strlen(webbuf));
if(x < 0)
{
printf("Error writing to web sock");
exit(1);
}
bzero(webbuf, 4096);
x = read(sockwb, webbuf, 4096);
if(n < 0)
{
printf("Error reading from web socket");
exit(1);
}
printf("%d\n", (int)strlen(webbuf));
printf("%s\n",webbuf);
n = write(newsockfd, webbuf, 4095 );//write back to client
if(n < 0)
{
fprintf(stderr, "ERROR WRITING to socket");
exit(1);
}
//printf("%s\n", webbuf);
}//end of if pid==0
printf("closing client");
close(newsockfd);//closing client socket
}while(1);
return 0;
}
The code you posted runs unimpeded. When you ask for help, you should always post a complete, verifiable example. Check that the code you post actually reproduces the problem!
Looking at what the code does, it seems that in the server, you meant to use the host name that you read as the argument to gethostbyname. You can do that with
host = &hostname[0];
or simpler
host = hostname;
or by not using two separate variables in the first place.
When you use an array in a context that expects a value (as opposed to e.g. taking its address or its sizeof), the array decays into a pointer to its first element. So here hostname is equivalent to hostname[0].
After that change, check the trace closely, or, to make the problem more visible, change the tracing line to
printf("[%s]\n", hostname);
You'll see
[aaa.com
]
The client reads a line with fgets, which includes the terminating newline character in its count. The client dutifully forwards the complete line to the server. And so the server looks up a host name containing a newline character, which doesn't exist. You don't check the return code of gethostbyname (you should!), it returns a null pointer, and the program crashes when it tries to read from it.
#Gilles is right, you have an '\n' at the end of the hostname, the following piece of code replaces the '\n' by 0 which is the equivalent of the character '\0':
extern int h_errno;
...
hostname[strlen(hostname) - 1] = 0;
wbhost = gethostbyname(hostname);
if (!wbhost) {
printf("Failed! %s\n", strerror(h_errno));
exit(1);
}
...
A char[] is an array of chars. A char* is a pointer to a char - generally (but not always) the start of a string.
If you want to get a pointer to the start of your array, you don't even need to do anything! This conversion happens implicitly:
char hello[6] = {'h', 'e', 'l', 'l', 'o', '\0'};
// or: char hello[] = "hello"; (equivalent to above)
printf("%s", hello); // prints hello
puts(hello); // also prints hello
char *hello2 = hello;
puts(hello2); // also prints hello
Probably the easiest way to 'convert' char[] to char * is:
char example_array[] = "example";
char * example_pointer = (char *)calloc(1, strlen(example_array) + 1); // + 1 for the '\0' character
strcpy(example_pointer, example_array);

observing erratic behavior while downloading(get) the file using socket

I have implemented the mget command using socket. But the output i am getting is having some random behavior. Sometime i am able to download the whole file on client, sometimes i am able to download files partially, sometime server code gives segmentation fault and sometimes client goes into infinite loop.
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 <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno;
socklen_t clilen;
// char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockfd < 0)
error("ERROR opening socket");
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)
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");
/*bzero(buffer,256);
n = read(newsockfd,buffer,255);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s\n",buffer);
n = write(newsockfd,"I got your message",18);
if (n < 0) error("ERROR writing to socket");*/
char command[512];
bzero(command, 512);
char buffer[4096];
char output[5000];
char f_size[20];
int send_bytes;
int written_bytes;
int total_sent_bytes = 0;
long int file_size;
n = recv(newsockfd, command, 512, 0); //try with MSG_WAITALL
if(n < 0)error("Error receiving command");
puts(command); //only file name
FILE * fp;
fp = fopen(command, "rb");
if(fp == NULL)error("Can not open requested file");
FILE * test_file_fp;
test_file_fp = fopen("test_file.txt", "wb");
if(test_file_fp == NULL)error("Can not open test file");
fseek(fp,0, SEEK_END);
file_size = ftell(fp);
rewind(fp);
sprintf(f_size,"%ld", file_size);
send(newsockfd, f_size, strlen(f_size), 0);
while(!feof(fp)){
bzero(buffer, 4096);
n = fread(buffer, sizeof(char), 4095, fp);
sprintf(output, "read bytes using fread = %d", n);
puts(output);
send_bytes = send(newsockfd, buffer, strlen(buffer) + 1, MSG_MORE);
total_sent_bytes += send_bytes;
sprintf(output, "sent bytes using send = %d", send_bytes);
puts(output);
written_bytes = fwrite(buffer, sizeof(char), strlen(buffer), test_file_fp);
sprintf(output, "written bytes using fwrite = %d", written_bytes);
puts(output);
//bzero(command, 512);
//recv(newsockfd, buffer, 512, 0);
puts("\n");
}
sprintf(output, "total sent bytes using send = %d\n", total_sent_bytes);
puts(output);
send(newsockfd, NULL, 1, 0);
fclose(test_file_fp);
fclose(fp);
close(newsockfd);
close(sockfd);
return 0;
}
Client Code:
#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;
int i;
// char buffer[5000];
if (argc < 3) {
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
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");
char command[512];
char output[5096];
int send_command_bytes;
int reveived_bytes;
char buffer[4096];
long int total_bytes;
long int total_received_bytes;
int written_bytes;
sprintf(output, "IP Protocol Number = %d", IPPROTO_TCP);
puts(output);
FILE * fp;
fp = fopen("received_file.txt", "wb");
if(fp == NULL)error("Could not open file for receiving data");
memcpy(command, "send_me.txt", 11);
send_command_bytes = send(sockfd, command, strlen(command), 0);
puts(command);
recv(sockfd, buffer, 4096, 0);
total_bytes = atoi(buffer);
sprintf(output, "Total bytes to be received = %ld", total_bytes);
puts(output);
total_received_bytes = 0;
while(totala_received_bytes < total_bytes){
bzero(buffer, 4096);
reveived_bytes = recv(sockfd, buffer, 4095, 0); //try with MSG_WAITALL, MSG_DONTWAIT
total_received_bytes += reveived_bytes;
sprintf(output, "Number of bytes received = %d", reveived_bytes);
puts(output);
written_bytes = fwrite(buffer, sizeof(char), strlen(buffer), fp);
sprintf(output, "Total written bytes = %d", written_bytes);
puts(output);
//send(sockfd, "1", 2, 0);
sprintf(output, "total Number of bytes received so far = %ld", total_received_bytes);
puts(output);
puts("\n");
}
fclose(fp);
close(sockfd);
return 0;
}
From client i am sending the file name "send_me.txt" which needs to be downloaded and this filename is being read by server in a buffer named command. This file is being opened in server and then read and then sent to client.
I have tried many possibilities to overcome this issue but the issue still persists.
Your code has both of the common problems when dealing with communications over sockets
1. Lack of NUL Termination
Strings in C are NUL terminated, so either you need to send the NUL as part of the message, or you need to add the NUL on the receive side.
2. Assumptions about message sizes
It's a common misconception in socket programming that each recv will match the corresponding send. For example, if I send 10 bytes, followed by 50 bytes, and later 20 bytes, then the expectation is that recv will need to be called three times, and will return 10 bytes, 50 bytes, and 20 bytes. That is completely, utterly, totally wrong. In fact, the first recv will return anywhere from 1 byte to 80 bytes. That is, it may return any portion of the data from the first send, up to all of the data from all of the sends.
Example from your code
In the server code, you do this
sprintf(f_size,"%ld", file_size);
send(newsockfd, f_size, strlen(f_size), 0);
If the file_size is 123, then the sprintf will write 1, 2, 3, \0 to f_size, i.e. three digits and a NUL terminator. The strlen will return 3, so the code only sends the three digits but doesn't send the NUL terminator.
On the client side, you have this
recv(sockfd, buffer, 4096, 0);
total_bytes = atoi(buffer);
Since the server doesn't send the NUL byte and the client doesn't add the NUL byte, the atoi will see whatever the recv put in the buffer, followed by garbage. If you're lucky, the first garbage character won't be a digit, and atoi will work correctly. If you're unlucky the first garbage character will be a digit.
In addition to the missing NUL, the recv may only get 1 byte, in which case the file size is 1 (assuming the first garbage character is not a digit). Or the recv may get 100 bytes (the 3 byte length plus some of the bytes from the file). If the file happens to start with digits, the size will be wrong.
Fixing the code
On the server side, send the file size as a fixed length message with the NUL included, e.g.
#define MSGLEN 24
char buffer[MSGLEN];
snprintf( buffer, MSGLEN, "%*ld", MSGLEN-1, file_size );
send( sockfd, buffer, MSGLEN, 0 );
On the client side, read in a loop until you have all of the bytes for the size, but no more
#define MSGLEN 24
char buffer[MSGLEN];
int count = 0;
int index;
for ( index = 0; index < MSGLEN; index += count )
{
count = recv( sockfd, &buffer[index], MSGLEN - index, 0 );
if ( count <= 0 )
break;
}
if ( index != MSGLEN || buffer[MSGLEN-1] != '\0' )
{
printf( "bad file size\n" );
exit( 1 );
}
total_bytes = atoi( buffer );
One final note
while(!feof(fp))-is-always-wrong

sprintf / snprintf not correctly writing to buffer

I have to write a TCP server program that holds an integer, that should be modifiable by the client programs. It should kind of resemble a bankaccount. Everything works fine, except one thing:
When a client first connects to the server, it will wait for a welcoming message (the server has to be iterative, so it should only handle one client at a time). The server always just sends the first couple of letters of the welcoming message. All other messages are transferred completely and correctly.
In line 49, the welcoming message is first copied to a char-array and then written to the socket. This is where the error is... Only the first 1-5 letters are sent (different each time a new client connects). In other places where I use sprintf() to copy a message to a char-array and then writing it to the socket, everything works just like I want it to.
I have also tried using snprintf(), but that doesn't work either. What am I doing wrong? :D
So this would be an example output on client side:
Connected!
Waiting for welcome message...
We
After that, I could start entering commands to the server. But the whole welcome message is cut of after two letters. But as said above, sometimes its just one letter, sometimes its five :D.
Anyway, here's my code (if there are any other errors or things I should avoid, feel free to tell me :D):
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>
#define BufferSize 99999
void error(const char *msg) {
fprintf(stderr, "%s\n", msg);
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[]) {
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char msg[BufferSize], data[BufferSize];
if (argc < 3) error("usage: <hostname> <port>\n");
server = gethostbyname(argv[1]);
if (server == NULL) error("Host not found!");
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) error("socket() error");
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("connect() error");
printf("Connected!\nWaiting for welcome message...\n");
memset(msg, 0, BufferSize);
n = read(sockfd, msg, BufferSize - 1);
if (n < 0) error("read() error");
printf("%s\n", msg);
memset(data, 0, BufferSize);
while (fgets(data, BufferSize, stdin) != NULL) {
data[strlen(data) - 1] = '\0'; //remove trailing newline char
n = write(sockfd, data, strlen(data) + 1);
if (n < 0) error("write() error");
if (strcmp(data, "exit") == 0) break;
memset(msg, 0, BufferSize);
n = read(sockfd, msg, BufferSize - 1);
if (n < 0) error("read() error");
if (n==0) error("Server shut down...");
printf("%s\n", msg);
memset(data, 0, BufferSize);
}
close(sockfd);
return 0;
}
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 <limits.h>
#define BufferSize 99999
#define ClientWaiting 100
void error(const char *msg) {
fprintf(stderr, "%s\n", msg);
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[]) {
int sockfd, newsockfd, portno, n, amount, balance, balOld;
socklen_t clilen;
char msg[BufferSize], data[BufferSize], *splitBuf[2];
struct sockaddr_in serv_addr, cli_addr;
balance = 0;
if (argc < 2) error("usage: <port>");
portno = atoi(argv[1]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) error("socket() error");
memset(&serv_addr, 0, sizeof (serv_addr));
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("bind() error");
listen(sockfd, ClientWaiting);
while (1) {
printf("Waiting for new client...\n");
clilen = sizeof (cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0) error("accept() error");
printf("New connection accepted...\n");
memset(data, 0, BufferSize);
sprintf(data, "Welcome!\nPlease use the following commands:\n<put, get> <positive integer>\nBalance: %d€", balance);
n = write(newsockfd, data, strlen(msg) + 1);
if (n < 0) error("write() error");
while (1) {
splitBuf[0] = NULL;
splitBuf[1] = NULL;
memset(data, 0, BufferSize);
memset(msg, 0, BufferSize);
n = read(newsockfd, msg, BufferSize - 1);
if (n < 0) {
fprintf(stderr, "read() error\n");
break;
}
if (n == 0) {
printf("Client disconnected...\n");
break;
}
printf("Message received: %s\n", msg);
if (strcmp(msg, "exit") == 0) break;
splitBuf[0] = strtok(msg, " ");
splitBuf[1] = strtok(NULL, " ");
if (splitBuf[1] == NULL) {
strcpy(data, "Please use the following commands:\n<put, get> <positive integer>");
} else {
amount = atoi(splitBuf[1]);
if (amount <= 0) {
strcpy(data, "Please use the following commands:\n<put, get> <positive integer>");
} else if (strcmp(splitBuf[0], "put") == 0) {
balOld = balance;
balance += amount;
if (balance < balOld) {
balance = INT_MAX;
sprintf(data, "Warning! Overflow!\nBalance: %d€", balance);
} else {
sprintf(data, "Balance: %d€", balance);
}
printf("New balance: %d€\n", balance);
} else if (strcmp(splitBuf[0], "get") == 0) {
balOld = balance;
balance -= amount;
if (balance > balOld) {
balance = INT_MIN;
sprintf(data, "Warning! Underflow!\nBalance: %d€", balance);
} else {
sprintf(data, "Balance: %d€", balance);
}
printf("New balance: %d€\n", balance);
}
}
n = write(newsockfd, data, strlen(data) + 1);
if (n < 0) error("write() error");
}
close(newsockfd);
}
close(newsockfd);
close(sockfd);
return 0;
}
This example is way too long for people on SO to debug. (We're not compilers and debuggers.)
Your first step must be decomposing the program into smaller, more easily understood pieces that can be debugged independently. There are a couple of ways of doing that:
adding checkpoints that test your assertions
breaking code into more easily understandable and independently testable functions
For example, I look at:
splitBuf[0] = strtok(msg, " ");
splitBuf[1] = strtok(NULL, " ");
Does splitBuf contain what you expect? (Is NULL a valid parameter to strtok?)
I recommend two things:
#include
# Are my assumptions met?
assert( splitBuf[0]!=null );
assert( splitBuf[1]!=null );
#ifdef DEBUG
printf("splitBuf[0]=%s\n", splitBuf[0]);
printf("splitBuf[1]=%s\n", splitBuf[1]);
#endif
Compile with -DDEBUG=1 to ensure that DEBUG is defined, or add:
#define DEBUG
at the top of the file.
Second, programming is much easier if you tackle smaller problems, then work on and test your answers to those problems independently. Let's say you need to parse a message from the network and extract a balance, then you might write:
int parseBalance(char const* serverMessage) {
...
return balance;
}
You can now write a test:
void tests()
{
// test parseBalance
assert( 100 == parseBalance("100") )
... more tests
}
Minimally, you could call tests() at the start of your program to perform a self-test (read up on "unit testing" for better approaches).
IF you program in this way:
often the problems will become more easily apparent
if you are stuck and post to SO, you only need to post the minimal function and test case.
I believe your problem is in your first read() call. You do a single read, expecting to get all of the welcome message. But that isn't how TCP works. TCP puts the stream data into packets according to its own internal rules, and the receiving system can make it available in any amount it wants.
You cannot rely on getting all of the data the server wrote in a single read.
In fact the server is messed up too. You cannot expect a write call to write everything you say. The operating system's send buffer for the socket might be full or it might have had a signal interrupt the call.
You need send and receive buffers and functions to handle a loop around read and write that continues until you receive a complete line or send a complete buffer.

Resources