Related
server.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
void error(char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno, clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
char *result1 = "Ian G. Harris";
char *result2 = "Joe Smith";
char *result3 = "Jane Smith";
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");
}
while (strcmp(buffer, "+++") != 0)
{
bzero(buffer,256);
n = read(newsockfd,buffer,255);
if (n < 0) error("ERROR reading from socket");
printf("Address server started\n");
if (strcmp(buffer, "harris#ics.uci.edu\n") == 0)
{
printf("%s\n", result1);
}
else if(strcmp(buffer, "joe#cnn.com\n") == 0)
{
printf("%s\n", result2);
}
else if(strcmp(buffer, "jane#slashdot.org\n")==0)
{
printf("%s\n", result3);
}
}
return 0;
}
client.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
void error(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");
while (strcmp(buffer, "+++") != 0)
{
printf("> ");
bzero(buffer,256);
fgets(buffer,255,stdin);
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);
}
return 0;
}
I am new to c and I am writing a server.c and client.c. The problem of my code is that I cannot make the program keep taking inputs until I enter "+++" to quit. The correct output is shown below:
client terminal:
> harris#ics.uci.edu
Ian G. Harris
> joe#cnn.com
Joe
>
server terminal:
Address server started
harris#ics.uci.edu
joe#cnn.com
in my code, when I enter "harris#ics.uci.edu" in client terminal, it does the following:
> harris#ics.uci.edu
(empty line)
and it does not take any input anymore.
Is there something wrong in the while loop? can someone help me to fix it? Thanks in advance.
Few things:
In the client loop, you do a write and a read on the socket. But your server never writes to that socket(no write call in the server, only read). As a result, your client gets blocked on the read call. That's why you cannot enter more...
In general, you need to check how much you wrote in and keep writing until done (a loop is needed).
int n = 0;
while (n != strlen(buffer){
n += write(sockfd,&buffer[n],strlen(buffer)-n);
}
Same goes for reading from a socket:
int n = 0;
while (n != strlen(buffer){
n += read(sockfd,&buffer[n],strlen(buffer)-n);
}
Here's what I believe is likely happening.
Client sends some chunk of data. Possibly all of the string harris#ics.uci.edu, but possibly less.
The server reads some chunk of this, most likely less than the full string, say harris#ic.
The server performs the strcmp, which doesn't match anything, so returns to the top of the loop.
The server reads the remainder of the email, say s.uci.edu into buffer, thus overwriting it.
Again, this doesn't match anything, so the server goes to the top of the while loop again.
The server hangs on the read call, waiting for data from the client. Because the client is waiting for a reply, it's stuck on its own read call. ...And nothing else happens.
There are two main problems here. First, TCP sockets are just streams of bytes, and when you read data from them, the OS no longer keeps it around. You are now expected to handle any previously- or partially-read data if you need. And second, the OS often transmits (both sending and receiving) fewer bytes than you request. While you ask that the full string harris#ics.uci.edu be sent, only a portion of that may be sent, or only a portion of that may be read on the other side.
This means two things for you. It's always important to check the amount of data read/written any time you call read(2) or write(2), but it's crucial in networking. Make sure you read/write as much as you need (the full email in this case) before moving on to, for example, waiting for a reply.
The second thing is that you need some way of delineating full messages and buffering partial messages. In what you've got, as is common in lots of text-based messaging protocols, the newline \n is your delimiter. So instead of a single call to read(2) in the server, you need something like this (pseduocode):
while newline not in data:
data += read(sockfd, ...)
Once you receive your newline, process the full message, but don't throw away any extra bytes you've read from the next message. Keep those around, and append the next bytes read from the socket to them, and so on.
EDIT:
Note that it's usually better to use recv(2) and send(2) when working with sockets. The read(2)/write(2) system calls will work just fine, but the others are more clear when working with sockets, and allow you to specify other flags, for example, peeking at the bytes currently on the socket or waiting until all the bytes you request are available before returning.
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.
I have this program that i can run with a port number then in browser do something like localhost:port/image.jpg and it will open the image. However i want to try and do this using threads.
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <strings.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#define BufferSize 1024 // for parsing request
#define BIG_ENUF 4096 // For request header
void error(char *); // prototype for quick error exit
int main(int argc, char *argv[]) // arv[1] has port #
{
int sockfd, newsockfd, portno, clilen,Connect_Count=0;
char buffer[BufferSize]; // for communicating with client
char * BigBuffer; // for serving file to client
int BufferNdx,n ;// workaday subscripts
char * TmpBuffer, *SavePtr, *FileName, *GetToken;
pid_t pid; // for forks;
FILE * F; // for streaming file when GET served
struct stat S;// to find file length
struct sockaddr_in serv_addr, cli_addr;
// structs for client and server
if (argc < 2) { // looking for port #
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
// specifies TCP IP flow
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); // proper byte order
if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
error("ERROR on binding");
GetToken = strtok_r(TmpBuffer," ",&SavePtr);
// And Now port is bound to socket for TCP / IP
while (Connect_Count < 10) // Limit on Number of Connections
{listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
// listen blocks until someone knocks and when we accept
// the client structure is filled by accept
if (newsockfd < 0) // exit server if bad accept
error( "ERROR on accept");
// otherwise let's fork a process to do that work
pid = fork();
if (pid < 0) error("bad fork\n");
if (pid == 0) break;
// to handle talking with client below
//if parent, loop again to listen if more connections ?
}
// ===================================================
// Forked child
memset(buffer, 0,BufferSize);
n = read(newsockfd,buffer,BufferSize-1); // This leaves null at end
if (n < 0) error("ERROR reading from socket");
printf("%s\n",(TmpBuffer=strtok_r(buffer,"\n",&SavePtr)));
GetToken = strtok_r(TmpBuffer," ",&SavePtr);
printf("%s\n",GetToken);
GetToken = strtok_r(NULL," ",&SavePtr);
printf("%s After Get\n",GetToken); // file name token begins '/'
GetToken++; // Point to first character of actual file name
// now open the file and send it to client ?
if ((F = fopen(GetToken,"r")) == NULL) error("Bad\n");
else printf("Good\n");
int FileSize;
if ((fstat(fileno(F),&S)==-1)) error("failed fstat\n"); // Need file size
FileSize = S.st_size;
char Response[BIG_ENUF];int HeaderCount=0;
HeaderCount=0;//Use to know where to fill buffer with sprintf
HeaderCount+=sprintf( Response+HeaderCount,"HTTP/1.0 200 OK\r\n");
HeaderCount+=sprintf( Response+HeaderCount,"Server: Flaky Server/1.0.0\r\n");
HeaderCount+=sprintf( Response+HeaderCount,"Content-Type: image/jpeg\r\n");
HeaderCount+=sprintf( Response+HeaderCount,"Content-Length:%d\r\n",FileSize);
//delimit header
HeaderCount+=sprintf( Response+HeaderCount,"\r\n");
fprintf(stderr,"HeaderCount %d and Header\n",HeaderCount);
write(STDERR_FILENO, Response, HeaderCount);
write(newsockfd,Response,HeaderCount); // and send to client
BigBuffer = malloc(FileSize+2);
fread(BigBuffer,1,FileSize,F);
write(newsockfd,BigBuffer,FileSize);
free(BigBuffer);
// Now close up this client
close(newsockfd);
return 0;
}
// bad error routine
void error(char *msg)
{
perror(msg);
exit(1);
}
I'm trying to convert these processes into a threads program. I'm very new to threads. But is the basic concept to move everything i have labeled under the child process to the thread function? and replace the forking with pthread_create s?
I have a simple Client and Server program in C, communicating via TCP. The client sends messages to the server and the server writes it to a file.
I need the client to loop indefinitely, until it reads an EOF character, and for the server to keep servicing the requests. However, at the moment I am getting issues with the looping. It works fine without any loops, but when I put a while(1) in the client the server services the first request fine but the second doesn't do anything and the third causes a broken pipe error. I think this is because the server closes the socket too early but I'm stuck on how to fix it.
Here's my Client program:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define BUFFERLENGTH 256
/* displays error messages from system calls */
void error(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[BUFFERLENGTH];
if (argc < 3) {
fprintf (stderr, "usage %s hostname port\n", argv[0]);
exit(1);
}
/* create socket */
portno = atoi (argv[2]);
sockfd = socket (AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error ("ERROR opening socket");
/* enter connection data */
server = gethostbyname (argv[1]);
if (server == NULL) {
fprintf (stderr, "ERROR, no such host\n"); // error message for when the provided hostname doesn't exist.
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 (portno);
/* connect to the server */
if (connect (sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0)
error ("ERROR connecting");
while(1){
/* prepare message */
printf ("Please enter the message: ");
bzero (buffer, BUFFERLENGTH);
fgets (buffer, BUFFERLENGTH, stdin);
/* send message */
n = write (sockfd, buffer, strlen(buffer));
if (n < 0)
error ("ERROR writing to socket");
bzero (buffer, BUFFERLENGTH);
/* wait for reply */
n = read (sockfd, buffer, BUFFERLENGTH -1);
if (n < 0)
error ("ERROR reading from socket");
printf ("%s\n",buffer);
}
return 0;
}
And Server code:
/* A threaded server which uses TCP to communicate with clients.
Passes the port number and a file name in as arguments.
Receives log entries from the clients and writes them to the file. */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <ctype.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#define BUFFERLENGTH 256
/* displays error messages from system calls */
void error(char *msg)
{
perror(msg);
exit(1);
}
FILE *file;
int returnValue;
pthread_mutex_t mut; /* the lock */
/* the procedure called for each request */
void *processRequest (void *args) {
int *newsockfd = (int *) args;
char buffer[BUFFERLENGTH];
int n, formed = 0;
n = read (*newsockfd, buffer, BUFFERLENGTH -1);
if (n < 0)
error ("ERROR reading from socket");
printf ("Here is the message: %s\n",buffer);
pthread_mutex_lock (&mut); /* lock exclusive access to variable isExecuted */
//const char* string = "hello world";
char buffer2[256];
char* walker;
int colon = 0;
strcpy(buffer2,buffer);
walker=buffer2;
while(colon == 0){
if(*walker == ':'){ // if it encounters a colon will successfully exit the loop.
colon = 1;
}
if(*walker == '\0'){ // if it encounters the end of the string, will break the loop.
break;
}
if(isalnum(*walker)){ // if it's not an alphanumeric character then it will break the loop, otherwise it will continue.
walker++;
} else {
break;}
}
if(colon == 1){ // if the loop found a colon, then it will continue to search the rest of the string.
while(*walker >= 32 && *walker<= 126){
++walker;
if(*walker == '\n'){
printf("Entry well formed.\n");
fprintf(file,"%s",buffer); /*writes*/
fclose(file); /*done!*/
formed = 1;
}
}
} else{
perror("Entry not well formed.\n");
}
pthread_mutex_unlock (&mut); /* release the lock */
if(formed==1){
n = sprintf (buffer, "Message received and written to file.\n");
}else{
n = sprintf (buffer, "Message received but was not well formed and was not written to file.\n");
}
/* send the reply back */
n = write (*newsockfd, buffer, BUFFERLENGTH);
if (n < 0)
error ("ERROR writing to socket");
close (*newsockfd); /* important to avoid memory leak */
free (newsockfd);
returnValue = 0; /* cannot guarantee that it stays constant */
pthread_exit (&returnValue);
}
int main(int argc, char *argv[])
{
socklen_t clilen;
int sockfd, portno;
char buffer[BUFFERLENGTH];
struct sockaddr_in serv_addr, cli_addr;
pthread_t *server_thread;
int result;
if (argc < 3) {
fprintf (stderr,"ERROR, arguments: port filename.\n"); /* Error message for if there isn't enough arguments. */
exit(1);
}
/* create socket */
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);
/* bind it */
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
/* ready to accept connections */
listen (sockfd,5);
clilen = sizeof (cli_addr);
/* now wait in an endless loop for connections and process them */
while (1) {
file = fopen(argv[2], "a");
if (file == NULL) {
printf("I couldn't open results.txt for writing.\n");
exit(0);
}
int *newsockfd; /* allocate memory for each instance to avoid race condition */
pthread_attr_t pthread_attr; /* attributes for newly created thread */
newsockfd = malloc (sizeof (int));
if (!newsockfd) {
fprintf (stderr, "Memory allocation failed!\n");
exit (1);
}
/* waiting for connections */
*newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
if (*newsockfd < 0)
error ("ERROR on accept");
bzero (buffer, BUFFERLENGTH);
/* create separate thread for processing */
server_thread = malloc (sizeof (pthread_t));
if (!server_thread) {
fprintf (stderr, "Couldn't allocate memory for thread!\n");
exit (1);
}
if (pthread_attr_init (&pthread_attr)) {
fprintf (stderr, "Creating initial thread attributes failed!\n");
exit (1);
}
if (pthread_attr_setdetachstate (&pthread_attr, !PTHREAD_CREATE_DETACHED)) {
fprintf (stderr, "setting thread attributes failed!\n");
exit (1);
}
result = pthread_create (server_thread, &pthread_attr, processRequest, (void *) newsockfd);
if (result != 0) {
fprintf (stderr, "Thread creation failed!\n");
exit (1);
}
}
return 0;
}
Note that you server code has been pasted badly and contains several copies of main() mixed up.
In the server, you call accept() to receive the client connection. You then create a thread to handle the connection. This thread handles just one message and exits, yet it is supposed to be servicing all messages from the client until the client has had enough.
So you need to put a loop in the server thread to allow it to handle multiple messages.
Note that when I ran your server, the first message, handled by the thread, was received correctly (message read "hello") but was reported to be badly formed (message Entry not well formed.). Running on OS-X.
Note also that the line:
if (pthread_attr_setdetachstate (&pthread_attr, !PTHREAD_CREATE_DETACHED)) {
should not have the '!' in front of the constant PTHREAD_CREATE_DETACHED.
Suppose, I have a connected socket after writing this code..
if ((sd = accept(socket_d, (struct sockaddr *)&client_addr, &alen)) < 0)
{
perror("accept failed\n");
exit(1);
}
How can I know at the server side that client has exited.
My whole program actually does the following..
Accepts a connection from client
Starts a new thread that reads messages from that particular client and then broadcast this message to all the connected clients.
If you want to see the whole code... In this whole code. I am also struggling with one more problem that whenever I kill a client with Ctrl+C, my server terminates abruptly.. It would be nice if anyone could suggest what the problem is..
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <pthread.h>
/*CONSTANTS*/
#define DEFAULT_PORT 10000
#define LISTEN_QUEUE_LIMIT 6
#define TOTAL_CLIENTS 10
#define CHAR_BUFFER 256
/*GLOBAL VARIABLE*/
int current_client = 0;
int connected_clients[TOTAL_CLIENTS];
extern int errno;
void *client_handler(void * socket_d);
int main(int argc, char *argv[])
{
struct sockaddr_in server_addr;/* structure to hold server's address*/
int socket_d; /* listening socket descriptor */
int port; /* protocol port number */
int option_value; /* needed for setsockopt */
pthread_t tid[TOTAL_CLIENTS];
port = (argc > 1)?atoi(argv[1]):DEFAULT_PORT;
/* Socket Server address structure */
memset((char *)&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET; /* set family to Internet */
server_addr.sin_addr.s_addr = INADDR_ANY; /* set the local IP address */
server_addr.sin_port = htons((u_short)port); /* Set port */
/* Create socket */
if ( (socket_d = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
fprintf(stderr, "socket creation failed\n");
exit(1);
}
/* Make listening socket's port reusable */
if (setsockopt(socket_d, SOL_SOCKET, SO_REUSEADDR, (char *)&option_value,
sizeof(option_value)) < 0) {
fprintf(stderr, "setsockopt failure\n");
exit(1);
}
/* Bind a local address to the socket */
if (bind(socket_d, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
fprintf(stderr, "bind failed\n");
exit(1);
}
/* Specify size of request queue */
if (listen(socket_d, LISTEN_QUEUE_LIMIT) < 0) {
fprintf(stderr, "listen failed\n");
exit(1);
}
memset(connected_clients,0,sizeof(int)*TOTAL_CLIENTS);
for (;;)
{
struct sockaddr_in client_addr; /* structure to hold client's address*/
int alen = sizeof(client_addr); /* length of address */
int sd; /* connected socket descriptor */
if ((sd = accept(socket_d, (struct sockaddr *)&client_addr, &alen)) < 0)
{
perror("accept failed\n");
exit(1);
}
else printf("\n I got a connection from (%s , %d)\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
if (pthread_create(&tid[current_client],NULL,(void *)client_handler,(void *)sd) != 0)
{
perror("pthread_create error");
continue;
}
connected_clients[current_client]=sd;
current_client++; /*Incrementing Client number*/
}
return 0;
}
void *client_handler(void *connected_socket)
{
int sd;
sd = (int)connected_socket;
for ( ; ; )
{
ssize_t n;
char buffer[CHAR_BUFFER];
for ( ; ; )
{
if (n = read(sd, buffer, sizeof(char)*CHAR_BUFFER) == -1)
{
perror("Error reading from client");
pthread_exit(1);
}
int i=0;
for (i=0;i<current_client;i++)
{
if (write(connected_clients[i],buffer,sizeof(char)*CHAR_BUFFER) == -1)
perror("Error sending messages to a client while multicasting");
}
}
}
}
My client side is this (Maye be irrelevant while answering my question)
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
void error(char *msg)
{
perror(msg);
exit(0);
}
void *listen_for_message(void * fd)
{
int sockfd = (int)fd;
int n;
char buffer[256];
bzero(buffer,256);
printf("YOUR MESSAGE: ");
fflush(stdout);
while (1)
{
n = read(sockfd,buffer,256);
if (n < 0)
error("ERROR reading from socket");
if (n == 0) pthread_exit(1);
printf("\nMESSAGE BROADCAST: %sYOUR MESSAGE: ",buffer);
fflush(stdout);
}
}
int main(int argc, char *argv[])
{
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
pthread_t read_message;
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,&serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
bzero(buffer,256);
if (pthread_create(&read_message,NULL,(void *)listen_for_message,(void *)sockfd) !=0 )
{
perror("error creating thread");
}
while (1)
{
fgets(buffer,255,stdin);
n = write(sockfd,buffer,256);
if (n < 0)
error("ERROR writing to socket");
bzero(buffer,256);
}
return 0;
}
After accepting the connection, your recv() on the socket will return 0 or -1 in special cases.
Excerpt from recv(3) man page:
Upon successful completion, recv()
shall return the length of the message
in bytes. If no messages are available
to be received and the peer has
performed an orderly shutdown, recv()
shall return 0. Otherwise, -1 shall be
returned and errno set to indicate the
error.
So, if your client exited gracefully, you will get 0 from recv() at some point. If the connection was somehow lost, you may also get -1 and checking for appropriate errno would tell you if the connection was lost of some other error occured. See more details at recv(3) man page.
Edit:
I see that you are using read(). Still, the same rules as with recv() apply.
Your server can also fail when trying to write() to your clients. If your client disconnects write() will return -1 and the errno would probably be set to EPIPE. Also, SIGPIPE signal will be send to you process and kill him if you do not block/ignore this signal. And you don't as I see and this is why your server terminates when client presses Ctrl-C. Ctrl-C terminates client, therefore closes client socket and makes your server's write() fail.
See mark4o's answer for nice detailed explanation of what else might go wrong.
If the client program exits, then the OS on the client will close its end of the socket. When you call recv() it will return 0, or -1 with errno ECONNRESET if a TCP RST has been received (e.g. because you attempted to send data after the client had closed). If the whole client machine goes down, or the network becomes disconnected, then in that case you may not receive anything if the server is not trying to send anything; if that is important to detect, you can either send some data periodically, or set the SO_KEEPALIVE socket option using setsockopt() to force it to send a packet with no data after long periods (hours) of inactivity. When no acknowledgment is received, recv() will then return -1 with errno ETIMEDOUT or another error if more specific information is available.
In addition, if you attempt to send data on a socket that has been disconnected, by default the SIGPIPE signal will terminate your program. This can be avoided by setting the SIGPIPE signal action to SIG_IGN (ignore), or by using send() with the MSG_NOSIGNAL flag on systems that support it (Linux).