Sockets: premature disconnect - c

So I have a simple TCP echo server program here(IPv4) that seems to disconnect immediately after it receives a connection from a new client before the client sends a FIN packet.
Here's the echo server code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MAX_BUFFER 1024
#define PORT 4000
int main()
{
int lsock,csock, ret, in , i;
int yes = 1;
char buffer[MAX_BUFFER];
char* c;
struct sockaddr_in servaddr;
struct sockaddr_in cliaddr; // connector's address information
if((lsock = socket(AF_INET,SOCK_STREAM,0))<0){
perror("socket");
return -1;
}
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(lsock,(struct sockaddr*)&servaddr,sizeof(servaddr))==-1) {
perror("bind");
close(lsock);
return -1;
}
if(listen(lsock,5)==-1){
perror("listen");
close(lsock);
return -1;
}else{
printf("Server listening on port %i\n",PORT);
system("gnome-terminal");
}
while(1){
int len = sizeof(cliaddr);
bzero(&cliaddr,len);
if(csock = accept(lsock,(struct sockaddr*)&cliaddr,&len)==-1){
perror("accept");
exit(0);
}
printf("New client connected....\n");
in = recv(csock,(void*)&buffer,sizeof(buffer),0);
if(in==-1){
perror("recv");
close(csock);
exit(0);
}else if(in==0){
printf("client disconnected\n");
close(csock);
}else{
if(send(csock,(void*)buffer,sizeof(buffer),0)==-1){
perror("send");
close(csock);
}
}
}
return 0;
}
And for the the echo client application:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <linux/ioctl.h>
#define MAX_BUFFER 1024
void die(char *s)
{
perror(s);
exit(1);
}
int main()
{
int connector,flags,r;
int port;
int set = 1;
struct hostent* host;
struct in_addr in;
struct sockaddr_in rmaddr;
char sendbuffer[MAX_BUFFER];
char recvbuffer[MAX_BUFFER];
char hostname[INET_ADDRSTRLEN];
char* exit = "quit";
if((connector = socket(AF_INET,SOCK_STREAM,0))<0){
perror("socket");
return -1;
}
printf("\n");
printf("Enter the remote hostname(URL/IP4 address): ");
scanf("%s", hostname);
printf("\n");
printf("Enter the port number you wish to connect(on): ");
scanf("%u", &port);
printf("\n");
if(port==0){
printf("ERR0R: Port number must be between 1 & 65,535\n");
printf("\n");
printf("Enter the port number you wish to connect(on): ");
scanf("%u", &port);
printf("\n");
}
host = gethostbyname(hostname);
if(host==NULL){
perror("hostname");
return -1;
}
bzero(&rmaddr,sizeof(rmaddr));
rmaddr.sin_family = AF_INET;
rmaddr.sin_port = htons(port);
bcopy((char*)host->h_addr, (char*)&rmaddr.sin_addr.s_addr, host->h_length);
if(connect(connector,(struct sockaddr*)&rmaddr,sizeof(rmaddr))<0){
perror("connect");
close(connector);
return -1;
}else{
printf("\n");
printf("Connected to host: %s",hostname,"on port %u",port);
printf(" type 'quit' to disconnect\n");
printf("\n");
}
while(1){
int nbr,nbs;
nbr = 0;
printf(">");
scanf("%s",sendbuffer);
printf("\n");
if(sendbuffer==exit){
close(connector);
return 0;
}
nbs = send(connector,(void*)&sendbuffer,strlen(sendbuffer),MSG_NOSIGNAL);
printf("\n");
printf("bytes sent: %i\n",nbs);
printf("\n");
if(nbs < 0){
perror("send() failed");
close(connector);
return -1;
}
while(nbr < nbs){
nbr = recv(connector,(void*)&recvbuffer,strlen(recvbuffer),MSG_NOSIGNAL);
if(nbr < 0){
perror("recv() failed");
close(connector);
return -1;
}else if(nbr==0){
printf("recv(): connection closed prematurely");
close(connector);
return -1;
}else if(nbr > 0){
printf("bytes received: %i\n",nbr);
printf("\n");
printf(">>");
printf("%s",recvbuffer);
printf("\n");
}
}
}
EXIT:
close(connector);
return 0;
}
Now when I compile the code and then execute it, this is the output(after I connect using the echo client):
zermacr0yd#DALEK /usr/lib/gcc/x86_64-linux-gnu/4.7/include $ ./ES
Server listening on port 4000
New client connected....
recvmsg: Socket operation on non-socket
zermacr0yd#DALEK /usr/lib/gcc/x86_64-linux-gnu/4.7/include $
Now I've tried connecting the client to other hosts, like www.google.com on port 80 and the output is the same. Which is:
zermacr0yd#DALEK /usr/lib/gcc/x86_64-linux-gnu/4.7.3/include $ ./EC
Enter the remote hostname(URL/IP4 address): www.google.com
Enter the port number you wish to connect(on): 80
Connected to host: www.google.com type 'quit' to disconnect
>hi
bytes sent: 2
recv(): connection closed prematurelyzermacr0yd#DALEK /usr/lib/gcc/x86_64-linux-gnu/4.7.3/include $
So it's clear that the connection is getting through(that is, the server receives the SYN packet)but immediately afterwards it closes the connection. So it appears to be a problem with the recv() function but it might very well be a connect() issue. But when I try to connect to the loopback address when the server isn't running I get:
zermacr0yd#DALEK /usr/lib/gcc/x86_64-linux-gnu/4.7.3/include $ ./EC
Enter the remote hostname(URL/IP4 address): 127.0.0.1
Enter the port number you wish to connect(on): 5000
connect: Connection refused
zermacr0yd#DALEK /usr/lib/gcc/x86_64-linux-gnu/4.7.3/include $
So I'm confoozed: Is this a server side error or a client side error? I'm thinking that the recv() function on the server side fails, the server closes the connection and shuts down, and then the client doesn't know that the server isn't running until the user on the client side tries to send a message and no bytes are received. It might very well be the client disconnecting but that doesn't look likely.

This line is wrong. It is going to evaluate to TRUE or FALSE (value 0 or 1) every time.
if (csock = accept(lsock, (struct sockaddr*) & cliaddr, &len) == -1)
{
perror("accept");
exit(0);
}
Consequently when you try a socket operation on file descriptor 0 or 1 - normally stdin and stdout - you are going to get the error that you are seeing: recvmsg: Socket operation on non-socket
Change the line to this:
if ((csock = accept(lsock, (struct sockaddr*) & cliaddr, &len)) == -1)

In your orignal server code, you had:
if(csock = accept(lsock,(struct sockaddr*)&cliaddr,&len)<0){
perror("accept");
exit(0);
}
which you have now changed to:
if(csock = accept(lsock,(struct sockaddr*)&cliaddr,&len)==-1){
perror("accept");
exit(0);
} 
But the problem is the same. Here, csock is probably getting the value 0, which would correspond to the standard input, and would thus not be a socket. (I assume 0, because if it becomes 1, your server would have exited early with an accept error message from perror().) This is because the < and == operators have higher precedence that =. You can fix this by adding a set of parentheses around the assignment (I stated this clearly before Duck provided his answer), or placing the assignment before the check. Since it seems you did not actually attempt either of my suggestions until you saw Duck's answer, I will illustrate the second suggestion:
csock = accept(lsock,(struct sockaddr*)&cliaddr,&len);
if (csock == -1) {
perror("accept");
exit(0);
} 
Your client test is invalid since you are connecting to an HTTP port, expecting ECHO behavior. You cannot draw any conclusions other than web servers do not accept hi as input.
Your server code is not well designed. It is a single threaded iterative server, but it does not properly clean up the existing client connection before iterating to perform another blocking accept() call. Instead, the client should handle the client connection until the connection is terminated before looping back to accept(). There are alternatives (have a separate thread handle the client connection, or use event driven loop with select()/poll()/epoll()). However, given that this seems to be a learning project, just handle one connection at a time is fine. However, you need an inner loop to completely handle the client connection before you accept() again. In pseudo-code:
while (not done)
new_conn = accept()
while (new_conn != -1)
result = read(new_conn, buf, bufsize)
switch (result)
case -1:
perror("read") /* FALLTHROUGH */
case 0:
close(new_conn)
new_conn = -1
break
default:
write(new_conn, buf, result)
break
The illustration above fixes another issue with your server, in that you are writing the complete buffer on the new connection, when instead you should only be writing out the number of bytes read, which in your case is stored in the variable in. So, instead of:
if(send(csock,(void*)buffer,sizeof(buffer),0)==-1){
Do this instead:
if(send(csock,(void*)buffer,in,0)==-1){

You had an operator precedence problem in the line that calls accept(), as noted by Duck. That accounts for 'socket operation on non-socket'.
'Connection refused' occurs at the client when the server cannot be found. It therefore has nothing to do with the server code whatsoever.
In your client you need to call perror() immediately after detecting an error, not three printf()'s later. Otherwise you corrupt errno and print the wrong error.
There is no 'premature disconnect' here. Just a disconnect, and a very misleading error message of your own devising. You're reading in a loop. Somebody has to disconnect some time. If you connect that client to a real echo server, it will echo one response and it may well then close the connection.

So in addition to following Ducks suggestion and adding a receiving loop to the server code, I realized that part of the problem with the echo_client was the following lines:
while(1){
int nbr,nbs;
nbr = 0;
When I removed the line that initialized nbr(number-of bytes received) to zero, the client does not disconnect and it actually works as I intended it to.

Related

Server proceeding without waiting to read client command in C socket programming

I have a simple server and client written in C.
They communicate well until the very end of my program where the server seems to skip the "read" method and just proceeds, it'll print out a blank line at
printf("%s", playAgain);
Here is the end of the 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 <netdb.h>
#include <arpa/inet.h>
#define BACKLOG 10
char invalidPortNumber[] = "Please specify a port number between 2000 and 65535";
char intro[] = "Welcome to the prisoners dilemma";
char playGame[] = "Will you stay silent or betray the other prisoner?\nType S for silent or B for betray";
char option1[] = "The other prisoner betrayed you\nYou each get 2 years in prison";
char option2[] = "The other prisioner betrayed you\nYou get 3 years in prison, the other prisioner is set free";
char option3[] = "The other prisioner stayed silent\nYou are set free, the other prisioner gets 3 years in prison";
char option4[] = "The other prisioner stayed silent\nYou both get 1 year on a lesser charge";
int main(int argc, char *argv[]) {
if (argc < 2) {
printf("Run with port number as the argument\n");
exit(1);
}
int port = atoi(argv[1]);
if (port<2000 || port>65535){
printf("%s\n", invalidPortNumber);
exit(2);
}
//Struct to store information for IPv4 address
struct sockaddr_in serverAddress;
//Create socket for IPv4, reliable stream (TCP), default protocol
int serverSocket = socket(PF_INET, SOCK_STREAM, 0);
//Specify that IPv4 family addresses will be used
serverAddress.sin_family = AF_INET;
//Set the port number
serverAddress.sin_port = htons(port);
//Bind to all local interfaces for IP
serverAddress.sin_addr.s_addr = INADDR_ANY;
//Bind the created socket to the IP address specified in the sockaddr_in struct
bind(serverSocket, (struct sockaddr *) &serverAddress, sizeof(serverAddress));
//Listen for connections, allowing backlog of up to BACKLOG connection requests
listen(serverSocket, BACKLOG);
int play = 0;
while(1) {
//Struct to store info of connecting clients
struct sockaddr_in clientAddress;
socklen_t clientAddrSize = sizeof(clientAddress);
//Create a socket for the connection between the client and server
int connectionSocket = accept(serverSocket, (struct sockaddr *) &clientAddress, &clientAddrSize);
//Input buffer to store client's request
do{
char input[800];
memset(input, '\0', sizeof(input));
//Have intro to the game
write(connectionSocket, intro, sizeof(intro) - 1);
//Read client's input
read(connectionSocket, input, sizeof(input)-1);
if(strcmp(input,"Y\n")==0||strcmp(input,"y\n")==0){
write(connectionSocket, playGame, sizeof(playGame) - 1);
}
else if(strcmp(input,"N\n")==0||strcmp(input,"n\n")==0){
write(connectionSocket, "Okay, connection closed", sizeof("Okay, connection closed") - 1);
close(connectionSocket);
return 0;
}
//read clients choice
char clientChoice[2];
read(connectionSocket, clientChoice, sizeof(clientChoice)-1);
srand(time(NULL));
int random = rand();
if( random % 2 ==0 ){
char serverChoice[2] = "S";
if(strcmp(clientChoice, "S")==0){
write(connectionSocket, option4, sizeof(option4) - 1);
}
else if(strcmp(clientChoice, "B")==0){
write(connectionSocket, option3, sizeof(option3) - 1);
}
}
else {
char serverChoice[2] = "B";
if(strcmp(clientChoice, "S")==0){
write(connectionSocket, option2, sizeof(option2) - 1);
}
else if(strcmp(clientChoice, "B")==0){
write(connectionSocket, option1, sizeof(option1) - 1);
}
}
char playAgain[5];
read(connectionSocket, playAgain, sizeof(playAgain)-1);
printf("%s",playAgain);
if(strcmp(playAgain, "Play")==0){
printf("Playing again");
play=1;
}
}while(play==1);
}
//Close the server socket and terminate the program if the loop ever ends
close(serverSocket);
return 0;
}
That is the server.
And now here is the end of the Client
#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 <arpa/inet.h>
#define BACKLOG 10
char invalidPortNumber[] = "Please specify a port number between 2000 and 65535";
char intro[] = "Welcome to the prisoners dilemma";
int main(int argc, char *argv[]) {
char buffer[512];
char IPAddress[15];
int n;
if (argc < 2) {
printf("Run with host IP and port number as the argument\n");
exit(1);
}
int port = atoi(argv[1]);
if (port<2000 || port>65535){
printf("%s\n", invalidPortNumber);
exit(2);
}
//Struct to store information for IPv4 address
struct sockaddr_in serverAddress;
//Create socket for IPv4, reliable stream (TCP), default protocol
int serverSocket = socket(PF_INET, SOCK_STREAM, 0);
//Specify that IPv4 family addresses will be used
serverAddress.sin_family = AF_INET;
//Set the port number
serverAddress.sin_port = htons(port);
//Bind to all local interfaces for IP
serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1");
//Bind the created socket to the IP address specified in the sockaddr_in struct
int play=0;
if(connect(serverSocket, (struct sockaddr *) &serverAddress, sizeof(serverAddress))<0){
printf("Couldn't connect, make sure the server is running and port number is correct \n");
return 1;
}
//read intro from server
do{
bzero(buffer,512);
n = read(serverSocket,buffer,511);
printf("%s\n",buffer);
//ask user if they'd like to play
int validCommand=1;
do{
printf("Would you like to play? (Y/N) ");
bzero(buffer,512);
fgets(buffer,511,stdin);
if(strcmp(buffer, "Y\n")==0||strcmp(buffer, "N\n")==0){
validCommand=0;
}
else{
printf("Invalid command \n");
}
}while(validCommand==1);
//write whether user wants to play to server
n = write(serverSocket,buffer,strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
bzero(buffer,512);
//read response from server
n = read(serverSocket,buffer,511);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n",buffer);
if(strcmp(buffer, "Okay, connection closed")==0){
close(serverSocket);
return 0;
}
do{
bzero(buffer,512);
printf("Make your choice (B/S) ");
fgets(buffer,511,stdin);
if(strcmp(buffer, "B\n")==0||strcmp(buffer, "S\n")==0){
validCommand=0;
}
else{
printf("Invalid command \n");
validCommand=1;
}
}while(validCommand==1);
//write the users choice to the server
n = write(serverSocket,buffer,strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
bzero(buffer,512);
n = read(serverSocket,buffer,511);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n",buffer);
do{
bzero(buffer,512);
printf("Would you like to play again? (Play/Quit) ");
fgets(buffer,511,stdin);
if(strcmp(buffer, "Play\n")==0||strcmp(buffer, "Quit\n")==0){
validCommand=0;
}
else{
printf("Invalid command \n");
validCommand=1;
}
}while(validCommand==1);
//write the users choice to the server
if(strcmp(buffer, "Quit\n")==0){
printf("Closing Connection to server");
close(serverSocket);
return 0;
}
if(strcmp(buffer, "Play\n")==0){
printf("Playing again");
play=1;
n = write(serverSocket,buffer,strlen(buffer)-1);
if (n < 0)
error("ERROR writing to socket");
}
}while(play==1);
}
Both the client and server work for the Choice B/S, the client sends, and the server responds. I have no idea what could be wrong, but the server seems to not wait for the clients final command
First, I think the basic problem you're running into is the common misconception that 1 write corresponds to 1 read automagically. It doesn't.
The problem you mention is caused by your reads and writes being out of sync. You need to make sure that you are reading the same amount as you send each time. The server isn't "proceeding without waiting to read client command;" it has just already read and ignored it.
For instance, when the client does
write(serverSocket, buffer, strlen(buffer))
the server is going to be confused. If you don't send over the size of the string first, the server can't know when to stop reading. This is especially true since you don't send the NUL-terminator. This specific problem could be avoided by doing more processing on the client side. By checking the input against "Y" and "N" on the client, you can simplify the communication to simply sending over a one byte boolean value. This reduces the complexity of your code and the amount of communication required between server and client.
If you would like examples of how you might start improving this, or have questions, just ask in the comments.
Side notes:
1) You don't need to send the intro over the socket; it's already on the client side.
2) Boolean variables like validCommand are conventionally 0 for false and 1 for true. You seem to have this flipped in your code. It's not wrong per se, just confusing to read.

why Imap server send different output?

Network programming problem regarding imap-client. I am using Dovecod localhost for imap. When I use telnet to check the connection it work perfectly but when C use my C-code to check the connection server send me different output.
The C-code only get error for my loopback ip, it works perfectly when I use different ip to execute the programs.
Here is the output difference screenshot
this is the output diffrence while using telnet and c-code
I tried to change the code little bit but the error give same.
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <stdlib.h>
#define PORT_TIME 13
#define PORT_IMAP 143
#define MAXBUF 1024
int main(int argc,char *argv[])
{
int sockfd;
int n;
struct sockaddr_in dest;
char buffer[MAXBUF],p[MAXBUF],q[MAXBUF];
/*---Open socket for streaming---*/
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
{
perror("Socket");
exit(errno);
}
/*---Initialize server address/port struct---*/
bzero(&dest, sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_port = htons(PORT_IMAP);
if ( inet_aton(argv[1], &dest.sin_addr) == 0 )
{
perror(argv[1]);
exit(errno);
}
if ( connect(sockfd, (struct sockaddr*)&dest, sizeof(dest)) != 0 )
{
perror("Connect ");
exit(errno);
}
else
{
printf("Connected to %s\n",argv[1]);
}
bzero(buffer, MAXBUF);
recv(sockfd, buffer, sizeof(buffer), 0);
printf("%s", buffer);
bzero(buffer,MAXBUF);
bzero(p,MAXBUF);
bzero(q,MAXBUF);
printf(" Name: ");
scanf("%[^\n]%*c",q);
printf(" Password: ");
fgets(p,MAXBUF,stdin);
strcat(buffer,"a1 LOGIN ");
strcat(buffer,q);
strcat(buffer," ");
strcat(buffer,p);
printf("%s",buffer);
if(write(sockfd,buffer,sizeof(buffer))<0)
perror("error on writing");
bzero(buffer, MAXBUF);
recv(sockfd, buffer, sizeof(buffer), 0);
printf("%s", buffer);
bzero(buffer,MAXBUF);
strncpy(buffer,"a2 LIST \"\" \"*\"\r\n",16);
printf("%s",buffer);
if(write(sockfd,buffer,16)<0)
perror("error on writing");
bzero(buffer, MAXBUF);
recv(sockfd, buffer, MAXBUF, 0);
printf("%s", buffer);
close(sockfd);
return 0;
}
When i receive from server it should get me "a2 OK" according to my c-code but it get me "* OK"
The IMAP server is required to do some things in response to your commands, but not forbidden from doing other things.
Most importantly, it can react to incoming mail independently of what commands you send, and its output depends both on the commands you send and those other events to which it also reacts.
Some IMAP servers send occasional * OK whatever for no particular reason, just to keep NAT middleboxes from closing the connection. I don't know why your server sent that * OK, but it's permitted. The server has to eventually send a2 OK, but it can send zero, one, two or 500 * OK responses first. (* OK just means "not an error, not related to any command".)

C server socket closed but client socket still able send two more packages

I am learning socket on c. I have a client and a server, when the server closed the socket, the client still able to receive and sent to server two more packages before the send get a SIGPIPE signal. I don't know why. Can anyone help pls~
since the documentation said that if the send and recv have error then they will return -1. But this never happen in my case here.
Client side
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define BUFFERSIZE 255
#define MAXLENG 96
#define true 1
#define false 0
void exitp();
int main(int argc, char *argv[]){
signal(SIGPIPE, exitp);
// Check if the argument is match the requirement
if (argc != 3) {
fprintf(stderr, "Useage Error, should be follow by ip, and port\n" );
exit(1);
}
// Create the socket for the client, if the fd for the socket == -1, it means
// it created fail
int skfd = socket(AF_INET, SOCK_STREAM, 0);
if (skfd < 0){
fprintf(stderr, "Create socket failed\n" );
exit(1);
}
int PORT = atoi(argv[2]);
// Set up server argument
struct sockaddr_in server_addr;
memset(&server_addr, '0', sizeof(server_addr)); // addr for bin
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
// ip not vaild
if (inet_pton(AF_INET, argv[1], &server_addr.sin_addr) < 1){
fprintf(stderr, "IP address not correct\n" );
exit(1);
}
// create the connection
if (connect(skfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1){ // Connect to server
fprintf(stderr, "Connection Fail\n" );
exit(1);
}
char sentbuff[255], recvbuffer[255], input[255], request[100], concelbuffer[255];
// Send the request to the server
int nn;
int size = send(skfd, request, sizeof(request),0);
while(1){
if (recv(skfd, &recvbuffer,sizeof(recvbuffer),0) == -1){
printf("Server Closed\n");
break;
}
printf("%s",recvbuffer);
fgets(sentbuff, 255, stdin);
nn=send(skfd, &sentbuff, sizeof(sentbuff), 0);
if (nn == -1){
printf("Server Closed\n");
break;
}
}
return 0;
}
void exitp(){
printf("%s\n","Server Closed" );
exit(0);
}
server side I used shutdown and close for the acceptfd
send() just puts the data in the kernel socket buffer, it doesn't wait for the data to be transmitted or the server to acknowledge receipt of it.
You don't get SIGPIPE until the data is transmitted and the server rejects it by sending a RST segment.
It works this way because each direction of a TCP connection is treated independently. When the server closes the socket, it sends a FIN segment. This just tells the client that the server is done sending data, it doesn't mean that the server cannot receive data. There's nothing in the TCP protocol that allows the server to inform the client of this. So the only way to find out that it's not accepting any more data is when the client gets that RST response.
Informing the client that they shouldn't send anything more is usually done in the application protocol, since it's not available in TCP.

Data sending error in socket

I have made simple server and client in c.Client waits for server until server is started.When i start the server data transmission between server and client is happening as per my expectation.When i close the server(not client) and again restarts the server,the first string from client to server is not transmitting.and then afterwards the client can send strings to server.So after restarting server client can't transmit first string to server.
Here is my client code(client.c),
/*header*/
#include<signal.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
/*macros*/
/*size of the buffer*/
#define DATA_SIZE 200
/*function for thread*/
void *recieve_handler(void *);
/*stores the id of main thread*/
pthread_t main_id;
/*socket variable*/
int sockfd=0;
/*specifies the port number*/
#define PORT 5000
/*lenth of ip*/
#define LENGTH_OF_IP 100
int quit = 1;
void signal_handler(int n)
{
/*write null to server*/
write(sockfd,"",2);
/*close socket*/
close(sockfd);
printf("Exiting from applicationn");
exit(0);
}
int main(int argc, char *argv[])
{
/*buffer to send and receive*/
char received_data[DATA_SIZE],send_data[DATA_SIZE],server_ip[LENGTH_OF_IP],buf[DATA_SIZE]
,user_name[DATA_SIZE];
/*declare pointer for client config file*/
FILE* config_file;
/*flags*/
int clear = 1,server_port,usb_trap_on,n;
/*declaring socket object*/
struct sockaddr_in serv_addr;
/*thread declaration*/
pthread_t thread_id;
/*welcome messsage*/
printf("This is clientn");
printf("Enter somethingn");
printf("Server echos back the datan");
/*open client configuration file*/
if ((config_file = fopen("client.config","rw+")) == NULL)
{
printf("Could not open client config filen");
return 1;
}
/*parsing the file*/
while (fgets(buf, sizeof buf, config_file) != NULL) {
if (sscanf(buf,"IP=%s PORT=%d",server_ip,&server_port) == 2)
printf("%s %dn",server_ip,server_port);
if (fscanf(config_file,"usb_trap=%d",&usb_trap_on) == 1)
printf("usb flag is %dn",usb_trap_on);
}
/*create the socket*/
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
printf("n Error : Could not create socket n");
return 1;
}
/*By setsockopt kernal will release the socket
*if it is in use*/
if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&clear,sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
/*inialize all the variable of object serv_addr with 0*/
memset(&serv_addr, '0', sizeof(serv_addr));
/*AF_INET refers to addresses from the internet*/
serv_addr.sin_family = AF_INET;
/*specifies port address
*and The htons() function makes sure that numbers are stored
*in memory in network byte order, which is with the most
*significant byte first*/
serv_addr.sin_port = htons(server_port);
/* inet_pton - convert IPv4 and IPv6 addresses from text to binary form
* it returns 0 when coversion is unsucessful*/
if(inet_pton(AF_INET, server_ip, &serv_addr.sin_addr)<=0){
printf("n inet_pton error occuredn");
return 1;
}
/*connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))
*if connection is established then the memory for server will be
*allocated in client's memory
*and strting address of that memory is stored in scokfd
*i will return negative value if operation fails. */
while(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){
printf("Wating for server to connectn");
sleep(1);
}
printf("Connection is donen");
printf("enter somethingn");
/*signal handling*/
signal(SIGTSTP,signal_handler);
/*create the thread to receive data*/
if( pthread_create( &thread_id , NULL , recieve_handler , (void*)&sockfd) < 0) {
perror("could not create thread");
return 1;
}
while(1) {
/*clear the buffer*/
memset(received_data,0,DATA_SIZE);
/*read from server*/
n = read(sockfd,received_data,sizeof(received_data));
/*if read error is occurred*/
if (n < 0) {
printf("Can't read received_datan");
break;
pthread_exit(&n);
}
if(n == 0) {
printf("Can't read received_datan");
break;
}
puts(received_data);
}
pthread_cancel(&thread_id);
/*close socket*/
if(!close(sockfd))
printf("Socket is closedn");
printf("Server is sutdown!!!!!!!!!!!!!n");
system("./client");
return 0;
}
void *recieve_handler(void *socket_desc)
{
/*received data buffer*/
char send_data[DATA_SIZE];
/*status flag*/
int n;
/*if pointer is empty*/
if(socket_desc == NULL) {
printf("socket_desc is NULLn");
n = 0;
pthread_exit(&n);
}
/*socket number*/
int sock = *(int*)socket_desc;
/*infinite loop*/
while (1){
/*clear buffer*/
memset(send_data, '0', sizeof(send_data));
/*get data from user*/
gets(send_data);
if((write(sock, send_data, strlen(send_data)+1)) == -1)
{
/*write data to server*/
printf("could not writen");
break;
}
}
}
here is my server code(server.c),
/*header*/
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
/*macros*/
/*maximum client that can be connected to server*/
#define MAX_CLIENT 10
/*size of the buffer*/
#define DATA_SIZE 200
/*specifies the port number*/
#define PORT 7000
int listenfd;
void signal_handler(int n)
{
printf("In handler\n");
char recived_data[DATA_SIZE];
write(listenfd,"\0",2);
read(listenfd, recived_data, sizeof(recived_data));/*write null to server*/
write(listenfd,"\0",2);
/*close socket*/
close(listenfd);
printf("Exiting from application\n");
exit(0);
}
int main(int argc, char *argv[])
{
/*signal handling*/
signal(SIGTSTP,signal_handler);
/*to store the recived data*/
char recived_data[DATA_SIZE];
/*sockaddr_in is a structure defined in netinet/in.h file.we are creating object of that
*strucure. */
struct sockaddr_in serv_addr;
/*flags*/
int connfd = 0 , clear = 1 ;
/*welcome message*/
printf("This simple server\n");
printf("It will echo data to client\n");
printf("If quit is recived from client then server will be existed\n");
/*Created socket*/
if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
printf("Can't create socket\n");
}
/*By setsockopt kernal will release the socket
*if it is in use*/
if (setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&clear,sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
/*AF_INET refers to addresses from the internet*/
serv_addr.sin_family = AF_INET;
/*tells that any client can connect*/
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
/*specifies port address
*and The htons() function makes sure that numbers are stored
*in memory in network byte order, which is with the most
*significant byte first*/
serv_addr.sin_port = htons(PORT);
/*specifies port and adress of the socket*/
bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
/*it will listen for connection
*MAX_CLIENT specifies the maximum client server can handle*/
listen(listenfd, MAX_CLIENT);
/*accept will assign the memory to client in server's memory area.here
*connfd has starting adress of assigned memory to client in server
*memory.*/
connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);
/*inet_ntoa(serv_addr.sin_addr) will return the adress of client*/
printf("[Server] Server has got connected from %s.\n", inet_ntoa(serv_addr.sin_addr));
printf("server waiting\n");
while(1){
/*read the data from memory and put in buffer*/
if(read(connfd, recived_data, sizeof(recived_data))){
/*if quit is recived then break the loop*/
if(!strcmp(recived_data,"quit"))
break;
/*put data on screen*/
puts(recived_data);
/*echo the data back to client*/
if(write(connfd,recived_data,strlen(recived_data)+1) == -1)
break;
}
else
{
printf("Could not read\n");
}
}
read(connfd, recived_data, sizeof(recived_data));
printf("server exiting\n");
/*close socket*/
close(connfd);
return(0);
}
here is client.config file(which is used be client to get ip,port of server)
IP=192.168.3.17 PORT=7000
usb_trap=0
This is my output of client when server is first time connected,
This is client
Enter something
Server echos back the data
192.168.3.17 7000
usb flag is 0
Wating for server to connect
Wating for server to connect
Connection is done
enter something
hello
hello
i am jay
i am jay
Above output is as per my expectation.
Now below is my output of client when server is reconnected(server is disconnected ,and then started again)
Socket is closed
Server is sutdown!!!!!!!!!!!!!
This is client
Enter something
Server echos back the data
192.168.3.17 7000
usb flag is 0
Wating for server to connect
Wating for server to connect
Wating for server to connect
Wating for server to connect
Connection is done
enter something
hello
could not write
jay
jay
So in above output client can't write first string to server.
Client signal handler:
void signal_handler(int n)
{
/*write null to server*/
write(sockfd,"",2);
/*close socket*/
close(sockfd);
printf("Exiting from applicationn");
exit(0);
}
Everything wrong here that could be wrong. No error checking. You can't do I/O in signal handlers. You can't block in signal handlers. You don't need to 'write null to server'. Exiting the application will close the socket, or reset it.
Client:
while(1) {
/*clear the buffer*/
memset(received_data,0,DATA_SIZE);
Unnecessary. Remove.
if (n < 0) {
printf("Can't read received_datan");
A pointless message. You got an error. Print the error, with perror(), or by incorporating strerror() into the message.
if(n == 0) {
printf("Can't read received_datan");
An incorrect message. This situation is not the same as the previous one. You got end of stream. The peer has disconnected. Say so.
puts(received_data);
Wrong. The data received is only valid up to n bytes. The correct way to print it is via printf("%.*s", n, received_data);
Client 'receive handler':
void *recieve_handler(void *socket_desc)
Apart from the mis-spelling, why is this called a receive handler when it doesn't receive? and does send?
memset(send_data, '0', sizeof(send_data));
/*get data from user*/
gets(send_data);
You probably meant '\0' here, as there are numerous other backslashes missing from your code, but the memset() is completely unnecessary. Remove.
Server signal handler:
void signal_handler(int n)
{
printf("In handler\n");
char recived_data[DATA_SIZE];
write(listenfd,"\0",2);
read(listenfd, recived_data, sizeof(recived_data));/*write null to server*/
write(listenfd,"\0",2);
/*close socket*/
close(listenfd);
printf("Exiting from application\n");
exit(0);
}
This is all nonsense from start to finish. You can't do I/O in a signal handler; you can't do I/O with a listening socket; you can't block in a signal handler; and you don't need to do any of it. The operating system will either close or reset the socket. Either way the peer will find out via the return value of read() or recv().
Server loop:
if(read(connfd, recived_data, sizeof(recived_data))){
Incorrect. It is never correct to call read() or recv() without storing the return value into a variable. You have to test it for -1, test it for zero, and otherwise use it as the length of data received. You can't accomplish that without a variable. See your own client code for an example, after my corrections.
if(!strcmp(recived_data,"quit"))
Invalid. There is no guarantee that you will receive a null-terminated string. And you haven't checked for EOS or an error first.
puts(recived_data);
Invalid for the same reason as the puts() in the client as discussed above.
if(write(connfd,recived_data,strlen(recived_data)+1) == -1)
Invalid. The length of the data received is given by the return value of read() if positive, not by strlen(). See discussion above.
else
{
printf("Could not read\n");
}
See discussion above about indiscriminate error messages like this. No use at all.
read(connfd, recived_data, sizeof(recived_data));
What is this? Remove.
Problem is that you are not canceling the thread properly.
Use
pthread_cancel(thread_id);
instead of
pthread_cancel(&thread_id);
So now thread will be canceled.and that thread will not be lived.

No route to host error in socket programming

I am writing a simple client program which connects to a the ip address "172.31.1.34" and sends a message. Everything works fine but I am not able to recieve any message from the server. The error says "no route to host".
My 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>
int main()
{
struct sockaddr_in server,client;
int s1,s2,len;
int n;
char buffer[500];
strcpy(buffer,"GET http://172.31.1.34/ HTTP/1.0\n\n");
bzero((char *)&client,sizeof(client));
client.sin_port = htons(80);
client.sin_addr.s_addr = inet_addr("172.31.1.34");
client.sin_family = AF_INET;
s2 = socket(AF_INET,SOCK_DGRAM,0);
if(connect(s2,(struct sockaddr *)&client,sizeof(client)) == -1) {
perror("can't connect\n");
exit(1);
}
n = send(s2,buffer,strlen(buffer),0);
if(n < 0) {
perror("message not sent");
exit(1);
}
while(1) {
memset(buffer,0,sizeof(buffer));
n = recv(s2,buffer,500,0);
if(n < 0) {
perror("coudnot read");
exit(1);
}
buffer[n] = '\0';
printf("%s",buffer);
}
close(s2);
return 0;
}
Why are you using SOCK_DGRAM? That is for UDP packets. HTML uses TCP. You should use SOCK_STREAM
I have only briefly looked at your code, but at first glance it seems OK. However I would start with the obvious - maybe there is no route to the host....
Assuming you are on Linux or other Unix platform (including OSX), I would do the following:
ping 172.31.1.34. Note this does not guarantee the host is not available as ping may be blocked.
telnet 172.31.1.34. This should connect and you can enter your HTTP query directly
tcptraceroute 172.31.1.34 80
If all of these fail, the problem is the network, not your code.
On OSX, you can install tcptraceroute from "homebrew". On Linux use your normal package manager (or ask your system managers).
Try the code below instead:
client.sin_addr.s_addr = inet_addr("172.31.1.34");
inet_pton(AF_INET, "172.31.1.34", &client.sin_addr);

Resources