Client Server Looping causes broken pipe - C - c

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.

Related

Sending date and time as a TCP server welcome message

I have to insert this code:
time_t ticks = time(NULL);
snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
to change the message displayed when someone connect to the server, from "Hello student!\n" to the current time and date, but I don't know where copy those two lines of code in the program and what I have to modify in the code after copying those two lines.
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
const char MESSAGE[] = "Hello student!\n";
int main(int argc, char *argv[]) {
int simpleSocket = 0;
int simplePort = 0;
int returnStatus = 0;
struct sockaddr_in simpleServer;
if (argc != 2) {
fprintf(stderr, "Usage: %s <port>\n", argv[0]);
exit(1);
}
simpleSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (simpleSocket == -1) {
fprintf(stderr, "Could not create a socket!\n");
exit(1);
}
else {
fprintf(stderr, "Socket created!\n");
}
/* retrieve the port number for listening */
simplePort = atoi(argv[1]);
/* setup the address structure */
/* use INADDR_ANY to bind to all local addresses */
memset(&simpleServer, '\0', sizeof(simpleServer));
simpleServer.sin_family = AF_INET;
simpleServer.sin_addr.s_addr = htonl(INADDR_ANY);
simpleServer.sin_port = htons(simplePort);
/* bind to the address and port with our socket */
returnStatus = bind(simpleSocket,(struct sockaddr *)&simpleServer,sizeof(simpleServer));
if (returnStatus == 0) {
fprintf(stderr, "Bind completed!\n");
}
else {
fprintf(stderr, "Could not bind to address!\n");
close(simpleSocket);
exit(1);
}
/* lets listen on the socket for connections */
returnStatus = listen(simpleSocket, 5);
if (returnStatus == -1) {
fprintf(stderr, "Cannot listen on socket!\n");
close(simpleSocket);
exit(1);
}
while (1)
{
struct sockaddr_in clientName = { 0 };
int simpleChildSocket = 0;
int clientNameLength = sizeof(clientName);
/* wait here */
simpleChildSocket = accept(simpleSocket,(struct sockaddr *)&clientName, &clientNameLength);
if (simpleChildSocket == -1) {
fprintf(stderr, "Cannot accept connections!\n");
close(simpleSocket);
exit(1);
}
/* handle the new connection request */
/* write out our message to the client */
write(simpleChildSocket, MESSAGE, strlen(MESSAGE));
close(simpleChildSocket);
}
close(simpleSocket);
return 0;
}
Thank you for your answers
A little introduction: about the original program
The program starts creating a socket and setting it to listen to a specific port, passed as an argument to your program with a command line such as programName <port>.
The port number is retrieved with the line simplePort = atoi(argv[1]);. There could have been a stricter check on the parameter (atoi() doesn't check if a number is actually provided), but I suppose it is ok for an entry level educational program.
After that, with the line
simpleChildSocket = accept(simpleSocket,(struct sockaddr *)&clientName, &clientNameLength);
the accept() function blocks until a connection request from a TCP client is received. As soon as the TCP handshake is completed (SYN / SYN-ACK / ACK, it is
called three-way handshake) a socket handle is returned (in your case simpleChildSocket) and that can be used to exchange data with the client.
The welcome message
After the accept is completed, and we are sure that all went fine, we soon come to our welcome message. With the lines
/* write out our message to the client */
write(simpleChildSocket, MESSAGE, strlen(MESSAGE));
the characters contained in the MESSAGE string (defined with the constant const char MESSAGE[] = "Hello student!\n";) are sent through write() function. Its parameters are
the socket descriptor
the pointer to the buffer to be sent
the number of bytes to be sent (in this case it corresponds to the length of MESSAGE, calculated with strlen(MESSAGE)
Note: write function can actually be used, but it is an unconventional choice. In fact it is a general function but when writing to sockets send() is actually used.
How to achieve you goal
All you have to do is to substitute MESSAGE in the write() call with the string containing the date:
{
char buff[30+1];
time_t ticks = time(NULL);
snprintf(buff, sizeof(buff), "%.30s\r\n", ctime(&ticks));
/* write out our message to the client */
write( simpleChildSocket, buff, strlen(buff) );
}
Don't forget to define your buff character buffer. I defined it locally but you can also allocate it dynamically.
The code provided by your teacher copies the time calculate with ctime() in the buff array (I increased its size in order to make sure that the whole datetime can be contained in it).
Then we call write as we previously did, just substituting MESSAGE and strlen(MESSAGE) with the new string buff and strlen(buff).
I have solved
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
/*const*/ char MESSAGE[100] = "";
char buff[100];
int main(int argc, char *argv[]) {
int simpleSocket = 0;
int simplePort = 0;
int returnStatus = 0;
struct sockaddr_in simpleServer;
if (argc != 2) {
fprintf(stderr, "Usage: %s <port>\n", argv[0]);
exit(1);
}
simpleSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (simpleSocket == -1) {
fprintf(stderr, "Could not create a socket!\n");
exit(1);
}
else {
fprintf(stderr, "Socket created!\n");
}
/* retrieve the port number for listening */
simplePort = atoi(argv[1]);
/* setup the address structure */
/* use INADDR_ANY to bind to all local addresses */
memset(&simpleServer, '\0', sizeof(simpleServer));
simpleServer.sin_family = AF_INET;
simpleServer.sin_addr.s_addr = htonl(INADDR_ANY);
simpleServer.sin_port = htons(simplePort);
/* bind to the address and port with our socket */
returnStatus = bind(simpleSocket,(struct sockaddr *)&simpleServer,sizeof(simpleServer));
if (returnStatus == 0) {
fprintf(stderr, "Bind completed!\n");
}
else {
fprintf(stderr, "Could not bind to address!\n");
close(simpleSocket);
exit(1);
}
/* lets listen on the socket for connections */
returnStatus = listen(simpleSocket, 5);
if (returnStatus == -1) {
fprintf(stderr, "Cannot listen on socket!\n");
close(simpleSocket);
exit(1);
}
while (1)
{
struct sockaddr_in clientName = { 0 };
int simpleChildSocket = 0;
int clientNameLength = sizeof(clientName);
/* wait here */
simpleChildSocket = accept(simpleSocket,(struct sockaddr *)&clientName, &clientNameLength);
if (simpleChildSocket == -1) {
fprintf(stderr, "Cannot accept connections!\n");
close(simpleSocket);
exit(1);
}
/* handle the new connection request */
/* write out our message to the client */
time_t ticks = time(NULL);
snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
strcpy(MESSAGE, buff);
write(simpleChildSocket, MESSAGE, strlen(MESSAGE));
close(simpleChildSocket);
}
close(simpleSocket);
return 0;
}

Presence of while/for loop causes abnormal execution

I have made small server and client programs to compare time taken for udp and tcp. So I have made a while loop for sending 100 messages. What the problem seems to be is that presence of loop in tdp client causes program to stop execution after certain line. The debug lines are also not being executed. I have never seen this kind of behaviour.
I expect the loop to exeute 100 times and output the time taken for those loops. But the otput is just
Connection to server:port 127.0.0.1:55057
/* usage: ./tcpclient host port */
#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 <netdb.h>
#include <time.h>
#include <arpa/inet.h>
#define BUFSIZE 1024
void error(char *msg) {
perror(msg);
exit(0);
}
int main(int argc, char **argv) {
int sockfd, portno, n;
struct sockaddr_in serveraddr;
struct hostent *server;
char *hostname;
char buf[BUFSIZE];
strcpy(buf, "hello");
clock_t start; int count=0;
/* check command line arguments */
if (argc != 3) {
fprintf(stderr,"usage: %s <hostname> <port>\n", argv[0]);
exit(0);
}
hostname = argv[1];
portno = atoi(argv[2]);
/* socket: create the socket */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
/* gethostbyname: get the server's DNS entry */
server = gethostbyname(hostname);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host as %s\n", hostname);
exit(0);
}
/* build the server's Internet address */
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serveraddr.sin_addr.s_addr, server->h_length);
serveraddr.sin_port = htons(portno);
/* connect: create a connection with the server */
if (connect(sockfd, &serveraddr, sizeof(serveraddr)) < 0)
error("ERROR connecting");
/* get message line from the user */
printf("Connection to server:port %s:%d\n",inet_ntoa(serveraddr.sin_addr),htons(portno));
printf("I never here here in presence of loop");
start = clock();
while(1){
/* send the message line to the server */
n = write(sockfd, buf, strlen(buf));
if (n < 0)
error("ERROR writing to socket");
/* print the server's reply */
n = read(sockfd, buf, BUFSIZE);
if (n < 0)
error("ERROR reading from socket");
printf("Echo from server: %s", buf);
}
printf("Time taken: %ld ",clock()-start);
close(sockfd);
return 0;
}
The line
printf("I never here here in presence of loop");
is not showing up because stdout is likely line-buffered and therefore output won't be visible until a newline is sent to stdout, or stdout is flushed.
If you change it to
printf("I never here here in presence of loop\n");
it will likely show up in your output.

ERROR on gethostbyaddr: Success

I am building a multiclient UDP server in c,but when i tried to connect to my server from a system, i get this error ERROR on gethostbyaddr: Success
Please find the below server code.I have tried the solutions from similar questions(gethostbyaddr() returns NULL but errno result in SUCCESS) but i couldn't get it working.Any help will be greatly appreciated
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define BUFSIZE 1024
/*
* error - wrapper for perror
*/
void error(char *msg) {
perror(msg);
exit(1);
}
int main(int argc, char **argv) {
int sockfd; /* socket */
int portno; /* port to listen on */
int clientlen; /* byte size of client's address */
struct sockaddr_in serveraddr; /* server's addr */
struct sockaddr_in clientaddr; /* client addr */
struct hostent *hostp; /* client host info */
char buf[BUFSIZE]; /* message buf */
char *hostaddrp; /* dotted decimal host addr string */
int optval; /* flag value for setsockopt */
int n; /* message byte size */
FILE *fp; /* file variable */
char str[10];
int i = 0;
char userlist[10];
int array_size;
char line[256];
int cred,flag;
/*
* check command line arguments
*/
if (argc != 2) {
fprintf(stderr, "usage: %s <port>\n", argv[0]);
exit(1);
}
portno = atoi(argv[1]);
/*
* socket: create the parent socket
*/
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
/* setsockopt: Handy debugging trick that lets
* us rerun the server immediately after we kill it;
* otherwise we have to wait about 20 secs.
* Eliminates "ERROR on binding: Address already in use" error.
*/
optval = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
(const void *)&optval , sizeof(int));
/*
* build the server's Internet address
*/
bzero((char *) &serveraddr, sizeof(serveraddr));
memset(&serveraddr,0,sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons((unsigned short)portno);
/*
* bind: associate the parent socket with a port
*/
if (bind(sockfd, (struct sockaddr *) &serveraddr,
sizeof(serveraddr)) < 0)
error("ERROR on binding");
/*
* main loop: wait for a datagram, then echo it
*/
clientlen = sizeof(clientaddr);
while (1) {
/*
* recvfrom: receive a UDP datagram from a client
*/
bzero(buf, BUFSIZE);
n = recvfrom(sockfd, buf, BUFSIZE, 0,
(struct sockaddr *) &clientaddr, &clientlen);
if (n < 0)
error("ERROR in recvfrom");
/*
* gethostbyaddr: determine who sent the datagram
*/
hostp = gethostbyaddr((const char *)&clientaddr.sin_addr.s_addr,
sizeof(clientaddr.sin_addr.s_addr), AF_INET);
if (hostp == NULL)
error("ERROR on gethostbyaddr");
hostaddrp = inet_ntoa(clientaddr.sin_addr);
if (hostaddrp == NULL)
error("ERROR on inet_ntoa\n");
printf("server received datagram from %s (%s)\n",
hostp->h_name, hostaddrp);
printf("server received %d/%d bytes: %s\n", strlen(buf), n, buf);
fp = fopen("users.txt", "r");
while (fgets(line, sizeof(line), fp)) {
//printf("%s\n",line);
cred = strncmp(buf,line,strlen(line)-1);
//printf("%d",strlen(line)-1);
if(cred == 0){
printf("Authenticated....");
flag = 1;
break;
}
else{
printf("Invalid username/password");
}
}
fclose(fp);
gethostbyaddr() expects a pointer to a struct in_addr as 1st parameter, which would be &clientaddr.sin_addr for the code you show.
Form the relevant (Linux) documentation (man gethostbyaddr):
[...] The host address argument is a pointer to a struct of a type depending on the address type, for example a struct in_addr * (probably obtained via a call to inet_addr(3)) for address type AF_INET.
gethostbyaddr() sets the error code in h_errno not in errno.
Form the relevant (Linux) documentation (man gethostbyaddr):
RETURN VALUE
[...[ The gethostbyname() and gethostbyaddr() functions return the hostent structure or a null pointer if an error occurs. On error, the h_errno variable holds an error number.
The possible error code are given by the man-page as well:
ERRORS
The variable h_errno can have the following values:
HOST_NOT_FOUND
The specified host is unknown.
NO_ADDRESS or NO_DATA
The requested name is valid but does not have an IP address.
NO_RECOVERY
A nonrecoverable name server error occurred.
TRY_AGAIN
A temporary error occurred on an authoritative name server. Try again later.

Problem in udp socket programing in c

I complile the following C code of UDP client
after I run './udpclient localhost 9191' in terminal.I put "Enter Text= " as Hello, but it is showing error in sendto as below:
Enter text: hello
hello
: error in sendto()guest-1SDRJ2#md-K42F:~/Desktop$
"
Note: I open 1st the server port as below in other terminal
./server 9191.
I beleive there is no error in server code. The udp client is not passing message to server. If I don't use thread , the message is passing .But I have to do it by thread.
UDP client Code:
/* simple UDP echo client */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <pthread.h>
#define STRLEN 1024
static void *readdata(void *);
static void *writedata(void *);
int sockfd, n, slen;
struct sockaddr_in servaddr;
char sendline[STRLEN], recvline[STRLEN];
int main(int argc, char *argv[]) {
pthread_t readid,writeid;
struct sockaddr_in servaddr;
struct hostent *h;
if(argc != 3) {
printf("Usage: %s <proxy server ip> <port>\n", argv[0]);
exit(0);
}
/* create hostent structure from user entered host name*/
if ( (h = gethostbyname(argv[1])) == NULL) {
printf("\n%s: error in gethostbyname()", argv[0]);
exit(0);
}
/* create server address structure */
bzero(&servaddr, sizeof(servaddr)); /* initialize it */
servaddr.sin_family = AF_INET;
memcpy((char *) &servaddr.sin_addr.s_addr, h->h_addr_list[0], h->h_length);
servaddr.sin_port = htons(atoi(argv[2])); /* get the port number from argv[2]*/
/* create a UDP socket: SOCK_DGRAM */
if ( (sockfd = socket(AF_INET,SOCK_DGRAM, 0)) < 0) {
printf("\n%s: error in socket()", argv[0]);
exit(0);
}
pthread_create(&readid,NULL,&readdata,NULL);
pthread_create(&writeid,NULL,&writedata,NULL);
while(1)
{
};
close(sockfd);
}
static void * writedata(void *arg)
{
/* get user input */
printf("\nEnter text: ");
do {
if (fgets(sendline, STRLEN, stdin) == NULL) {
printf("\n%s: error in fgets()");
exit(0);
}
/* send a text */
if (sendto(sockfd, sendline, sizeof(sendline), 0, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) {
printf("\n%s: error in sendto()");
exit(0);
}
}while(1);
}
static void * readdata(void *arg)
{
/* wait for echo */
slen = sizeof(servaddr);
if ( (n = recvfrom(sockfd, recvline, STRLEN, 0, (struct sockaddr *) &servaddr, &slen)) < 0) {
printf("\n%s: error in recvfrom()");
exit(0);
}
/* null terminate the string */
recvline[n] = 0;
fputs(recvline, stdout);
}
The problem is that you're using the same sockaddr struct (servaddr) for both the sendto and revfrom calls. The recvfrom happens first, so it clears out servaddr in preparation for writing in the source address of the received packed (once it receives one -- that thread is still blocked in the kernel waiting for a packet). Then, when the sendto call occurs, the sockaddr is all zeros, so it immediately returns EINVAL.
You may be getting confused by the fact that the sockaddr argument to recvfrom is an OUTPUT, not an input -- it gets filled in with the source address of the packet that is received (which could be from anywhere). If you want to only receive packets from a particular place (the server?), you need to check the address after the recvfrom returns and toss the packet if it comes from somewhere else, looping back to recvfrom again.

How to know if the client has terminated in sockets

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).

Resources