I'm trying TCP file transfer on Linux. After establishing the connection, the server should send "send.txt" to the client, and the client receives the file and saves it as "receive.txt". Then the connection breaks.
The correct input and output should be:
Server terminal:
$./server &
[server] obtain socket descriptor successfully.
[server] bind tcp port 5000 in addr 0.0.0.0 successfully.
[server] listening the port 5000 successfully.
[server] server has got connect from 127.0.0.1.
[server] send send.txt to the client…ok!
[server] connection closed.
Client terminal:
$./client
[client] connected to server at port 5000…ok!
[client] receive file sent by server to receive.txt…ok!
[client] connection lost.
And both the server and client should exit after the process.
But what I've got now gives
$ ./server &
[server] obtain socket descriptor successfully.
[server] bind tcp port 5000 in addr 0.0.0.0 sucessfully.
[server] listening the port 5000 sucessfully.
[server] server has got connect from 127.0.0.1.
[server] send send.txt to the client...ok!
[server] connection closed.
/*Here the server doesn't exit*/
$ ./client
[client] connected to server at port 5000...ok!
/*Here the client doesn't exit*/
Also, an EMPTY "receive.txt" is generated.
My code was first written for transferring simple strings, and it worked correctly. So I guess the problem lies in the file transferring part.
My code is as follows:
server.c
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/socket.h>
#define PORT 5000 // The port which is communicate with server
#define BACKLOG 10
#define LENGTH 512 // Buffer length
int main ()
{
int sockfd; // Socket file descriptor
int nsockfd; // New Socket file descriptor
int num;
int sin_size; // to store struct size
struct sockaddr_in addr_local;
struct sockaddr_in addr_remote;
/* Get the Socket file descriptor */
if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
{
printf ("ERROR: Failed to obtain Socket Descriptor.\n");
return (0);
}
else printf ("[server] obtain socket descriptor successfully.\n");
/* Fill the local socket address struct */
addr_local.sin_family = AF_INET; // Protocol Family
addr_local.sin_port = htons(PORT); // Port number
addr_local.sin_addr.s_addr = INADDR_ANY; // AutoFill local address
bzero(&(addr_local.sin_zero), 8); // Flush the rest of struct
/* Bind a special Port */
if( bind(sockfd, (struct sockaddr*)&addr_local, sizeof(struct sockaddr)) == -1 )
{
printf ("ERROR: Failed to bind Port %d.\n",PORT);
return (0);
}
else printf("[server] bind tcp port %d in addr 0.0.0.0 sucessfully.\n",PORT);
/* Listen remote connect/calling */
if(listen(sockfd,BACKLOG) == -1)
{
printf ("ERROR: Failed to listen Port %d.\n", PORT);
return (0);
}
else printf ("[server] listening the port %d sucessfully.\n", PORT);
int success = 0;
while(success == 0)
{
sin_size = sizeof(struct sockaddr_in);
/* Wait a connection, and obtain a new socket file despriptor for single connection */
if ((nsockfd = accept(sockfd, (struct sockaddr *)&addr_remote, &sin_size)) == -1)
printf ("ERROR: Obtain new Socket Despcritor error.\n");
else printf ("[server] server has got connect from %s.\n", inet_ntoa(addr_remote.sin_addr));
/* Child process */
if(!fork())
{
char* f_name = "send.txt";
char sdbuf[LENGTH]; // Send buffer
printf("[server] send %s to the client...", f_name);
FILE *fp = fopen(f_name, "r");
if(fp == NULL)
{
printf("ERROR: File %s not found.\n", f_name);
exit(1);
}
bzero(sdbuf, LENGTH);
int f_block_sz;
while((f_block_sz = fread(sdbuf, sizeof(char), LENGTH, fp))>0)
{
if(send(nsockfd, sdbuf, f_block_sz, 0) < 0)
{
printf("ERROR: Failed to send file %s.\n", f_name);
break;
}
bzero(sdbuf, LENGTH);
}
printf("ok!\n");
success = 1;
close(nsockfd);
printf("[server] connection closed.\n");
while(waitpid(-1, NULL, WNOHANG) > 0);
}
}
}
client.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define PORT 5000
#define LENGTH 512 // Buffer length
int main(int argc, char *argv[])
{
int sockfd; // Socket file descriptor
char revbuf[LENGTH]; // Receiver buffer
struct sockaddr_in remote_addr;
/* Get the Socket file descriptor */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
printf("ERROR: Failed to obtain Socket Descriptor!\n");
return (0);
}
/* Fill the socket address struct */
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(PORT);
inet_pton(AF_INET, "127.0.0.1", &remote_addr.sin_addr);
bzero(&(remote_addr.sin_zero), 8);
/* Try to connect the remote */
if (connect(sockfd, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) == -1)
{
printf ("ERROR: Failed to connect to the host!\n");
return (0);
}
else printf("[client] connected to server at port %d...ok!\n", PORT);
//printf ("OK: Have connected to %s\n",argv[1]);
printf("[client] receive file sent by server to receive.txt...");
char* f_name = "receive.txt";
FILE *fp = fopen(f_name, "a");
if(fp == NULL) printf("File %s cannot be opened.\n", f_name);
else
{
bzero(revbuf, LENGTH);
int f_block_sz = 0;
int success = 0;
while(success == 0)
{
while(f_block_sz = recv(sockfd, revbuf, LENGTH, 0))
{
if(f_block_sz < 0)
{
printf("Receive file error.\n");
break;
}
int write_sz = fwrite(revbuf, sizeof(char), f_block_sz, fp);
if(write_sz < f_block_sz)
{
printf("File write failed.\n");
break;
}
bzero(revbuf, LENGTH);
}
printf("ok!\n");
success = 1;
fclose(fp);
}
}
close (sockfd);
printf("[client] connection lost.\n");
return (0);
}
Thank you very much!
You need to add code to the f_block_sz code. recv() has a few posible return values:
<0 -- Error, error number in errno (errno.h)
0 -- Connection closed
>0 -- Data read, number of bytes
You need to handle the second case. Add this else case:
else if(f_block_sz)
{
break;
}
So that the loop will be broken when the server closes the connection, and your code will print you [client] connection lost and exit.
You have another problem in that your server program is multiprocess and forks every time it gets an incoming connection. The parent stays alive to accept new connections and the child processes the connection. The exit from the child process is not enough to cause the parent to exit as well.
If you only want to process one connection then don't use fork.
If you wish to continue your current setup then you will need to change the child process to use _exit instead of exit and get the parent process to handle the SIGCHLD signal (received when a child process exits).
ie.
#include <signal.h>
void terminate(int signal) {
// close sockfd -- you will need to make it global
// or have terminate alter some global variable that main can monitor to
// detect when it is meant to exit
exit(0); // don't exit if you choose the second option
}
int main() {
signal(SIGCHLD, terminate);
...
}
Related
Both programs compile, and I'm able to successfully create a socket, but the connection to the server fails. This is basically a TCP echo program.
PS. I'm new here so IDK how to use this, I don't have much programming experience so bare with me.
tcp echo client-1
tcp echo client-2
tcp echo server-1
tcp echo server-2
Compiling/Running server gives me: Server not fully implemented...
Compiling/Running client gives me: Socket successfully created..Error: connection to the server failed!
**// TCP echo client program**
#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 <arpa/inet.h>
int main (int argc, char* argv[ ]) // Three arguments to be checked later
{
struct sockaddr_in servAddr; // Server socket address data structure
char *servIP = argv[1]; // Server IP address from command line
int servPort = atoi(argv[2]); // Server port number from command line
char *message = argv[3]; // Message specified on the command line
char buffer [512 + 1];
char* ptr = buffer;
int len;
int max_len = sizeof(buffer);
int sock_descrip;
// Check for correct number of command line arguments
if(argc != 4) {
printf("tcp-echo-client [IP address] [Port] [Message]\n");
exit (1);
}
// Populate socket address for the server
memset (&servAddr, 0, sizeof(servAddr)); // Initialize data structure
servAddr.sin_family = AF_INET; // This is an IPv4 address
servAddr.sin_addr.s_addr = inet_addr(servIP); // Server IP address
servAddr.sin_port = servPort; // Server port number
// Create a TCP socket stream
int sock;
if ((sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
printf("Error: socket creation failed!\n");
exit (1);
}
else
printf("Socket successfully created..\n");
// Connect to the server
if ((connect (sock, (struct sockaddr*)&servAddr, sizeof(servAddr))) == -1) {
printf("Error: connection to the server failed!\n");
exit (1);
}
else
printf("Connected to the server..\n");
// Send data to the server...
send(sock_descrip, message, strlen(message),0);
int x;
while ((x = recv(sock_descrip, ptr, max_len,0))>0)
{
ptr += x;
max_len -= x;
len += x;
}
buffer[len] = '\0';
printf("Echoed string received: %s %c", buffer,*message);
// Receive data back from the server..
// Loop while receiving data...
// print data...
// end-while loop
// Close socket
close (sock);
// Stop program
exit (0);
} // End main
**//TCP Echo server program**
#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 <arpa/inet.h>
#define BUFLEN 512 // Maximum length of buffer
#define PORT 9988 // Fixed server port number
int main (void)
{
struct sockaddr_in server_address; // Data structure for server address
struct sockaddr_in client_address; // Data structure for client address
int client_address_len = 0;
char buffer [512];
char* ptr = buffer;
int len;
int max_len = BUFLEN;
int sock_descrip;
// Populate socket address for the server
memset (&server_address, 0, sizeof (server_address)); // Initialize server address data structure
server_address.sin_family = AF_INET; // Populate family field - IPV4 protocol
server_address.sin_port = PORT; // Set port number
server_address.sin_addr.s_addr = INADDR_ANY; // Set IP address to IPv4 value for loacalhost
// Create a TCP socket; returns -1 on failure
int listen_sock;
if ((listen_sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
printf("Error: Listen socket failed!\n");
exit (1);
}
// Bind the socket to the server address; returns -1 on failure
if ((bind(listen_sock, (struct sockaddr *)&server_address, sizeof (server_address))) == -1) {
printf("Error: binding failed!\n");
exit (1);
}
printf("Server not fully implemented...\n");
// Listen for connections...
int wait_size;
if (listen(listen_sock, wait_size) == -1)
{
printf("Error: listening failed!\n");
exit(1);
}
for(;;)
{
if(sock_descrip=accept(listen_sock,(struct sockaddr *)&client_address, &client_address_len) == -1)
{
printf("Error: accepting failed!\n");
exit(1);
}
int x;
while ((x = recv(sock_descrip, ptr, max_len, 0)) > 0)
{
ptr += x;
max_len -= x;
len += x;
}
send(sock_descrip,buffer,len,0);
}
// Echo data back to the client...
close (listen_sock); // Close descriptor referencing server socket
} // End main
You need parentheses around the assignment:
if(
(sock_descrip=accept(listen_sock,(struct sockaddr *)&client_address, &client_address_len))
== -1)
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.
Is it possible that a TCP server program can listen on two different socket interface?
Problem Statement:
I've a problem statement where the TCP server will be having two interfaces:
Interface I: For accepting generic data from TCP client (IP address 192.168.5.10:2000)
Interface II: Management Interface for the server (IP address 192.168.5.11:2000)
Interface I: This interface shall receive data from TCP client, processes them & send it back to client.
Interface II: This interface shall receive commands (meant for Servers management purpose). This commands most probably would be sent through telnet.
Current Status:
I already have a thread based TCP server program where I've "Interface I" up & running(I'm able to receive data from multiple clients, process them & send it back)
Can anyone give me some pointers/prototype example on how to add "Interface II" to my TCP server program?
NOTE: TCP server program is written in C programming language for Linux OS
UPDATE
Below is the code fragment I've written so far for listening on one socket. I tried modifying it for listening over two sockets as you've directed but I'm facing trouble while trying to spawn a different thread for the other socket interface. Will it possible for you to modify this to listen on two sockets? It would be really helpful.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
void *data_processing_thread(void *arg);
int main(int argc, char **argv)
{
int fdmax, listener, newfd, res;
int optval=1;
socklen_t addrlen;
int server_port = 4000;
/* master, temp file descriptor list */
fd_set *master, *read_fds;
/* client, server address */
struct sockaddr_in server_addr, client_addr;
pthread_t thread;
master = malloc(sizeof(fd_set));
read_fds = malloc(sizeof(fd_set));
FD_ZERO(master);
FD_ZERO(read_fds);
/* create endpoint for communication */
if ((listener = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("failed to create listener\n");
return -1;
}
/* check if address is already in use? */
if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &optval,
sizeof(int)) == -1) {
perror("socket address already in use!\n");
return -1;
}
/* bind */
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(server_port);
memset(&(server_addr.sin_zero), '\0', 8);
if (bind(listener, (struct sockaddr*)&server_addr,
sizeof(server_addr)) == -1) {
perror("failed to do the bind\n");
return -1;
}
/* listen for connect on sockets */
if (listen(listener, 10) == -1) {
perror("failed to listen on socket\n");
return -1;
}
/* add the listener to the master set */
FD_SET(listener, master);
/* keep track of biggest file descriptor */
fdmax = listener;
while (1) {
read_fds = master;
/* wait till socket descriptor is ready for the operation */
if (select(fdmax+1, read_fds, NULL, NULL, NULL) == -1) {
perror("failed to do select() on socket\n");
return -1;
}
/* Run through existing data connections looking for data to be
* read */
int cnt;
int *accept_fd = 0;
for (cnt=0; cnt<=fdmax; cnt++) {
if (cnt == listener) {
if (FD_ISSET(cnt, read_fds)) {
addrlen = sizeof(client_addr);
if ((newfd = accept(listener, (struct sockaddr*)&client_addr, &addrlen)) == -1) {
perror("failed to accept incoming connection\n");
} else {
fprintf(stdout, "Server: Connection from client [%s] on socket [%d]\n",
inet_ntoa(client_addr.sin_addr), newfd);
accept_fd = malloc(sizeof(int));
*accept_fd = newfd;
if ((res = pthread_create(&thread, NULL, data_processing_thread, (void*)accept_fd)) != 0) {
perror("Thread creation failed\n");
free(accept_fd);
}
}
}
continue;
}
}
}
return 1;
}
void *data_processing_thread(void *arg)
{
int nbytes;
int *recv_fd = (int*)arg;
char *buffer = malloc(sizeof(char)*256);
while(1) {
fprintf(stdout, "Server: Waiting for data from socket fd %d\n", *recv_fd);
/* receive incoming data from comm client */
if ((nbytes = recv(*recv_fd, buffer, sizeof(buffer), 0)) <= 0) {
if (nbytes != 0) {
perror("failed to receive\n");
}
break;
} else {
fprintf(stdout, "Data received: %s\n", buffer);
}
}
close(*recv_fd);
free(recv_fd);
pthread_exit(0);
}
Create two listening sockets using socket().
Bind both to respective address/port using bind().
Make both listen using listen().
Add both listening sockets to a properly initialised fd_set typed variable using FD_SET().
Pass the fd_set to a call to select()
Upon select()'s return check the reason and perform the appropriate action, typically
either calling accept() on one of the both listening sockets and add the accepted socket (as returned by accept()) to the fd_set,
or if it's an accepted socket that had triggered select() to return, then call read(), write() or close() on it. If close()ing the socket also remove it from the fd_set using FD_CLR().
Start over with step 5.
Important note: The steps above are a rough scheme, not mentioning all possible all traps, so it is absolutly necessary to also read the related man-pages for each step carefully, to understand what is happening.
you can bind 0.0.0.0 which means binding all interfaces.
you can't bind two interfaces using only one socket.
you should create a new socket, and bind ti to interface II.
I am trying to make a file transfer between server and client, but is working very badly. Basically what needs to happen is:
1) The client send a txt file to the server (I called it "quotidiani.txt")
2) The server saves it in another txt file ("receive.txt")
3) The server runs a script on it that modifies it and saves it with another name ("output.txt")
4) The server send the file back to the client that saves it (on the same socket) with the name (final.txt)
The problem is that the first file (quotidiani.txt) is read just for a little part, and then there are some errors. I'd like someone to help me understand and correct my errors.
Here's my code:
client.c:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <signal.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <netdb.h>
#define PORT 20000
#define LENGTH 512
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
/* Variable Definition */
int sockfd;
int nsockfd;
char revbuf[LENGTH];
struct sockaddr_in remote_addr;
/* Get the Socket file descriptor */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
fprintf(stderr, "ERROR: Failed to obtain Socket Descriptor! (errno = %d)\n",errno);
exit(1);
}
/* Fill the socket address struct */
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(PORT);
inet_pton(AF_INET, "127.0.0.1", &remote_addr.sin_addr);
bzero(&(remote_addr.sin_zero), 8);
/* Try to connect the remote */
if (connect(sockfd, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) == -1)
{
fprintf(stderr, "ERROR: Failed to connect to the host! (errno = %d)\n",errno);
exit(1);
}
else
printf("[Client] Connected to server at port %d...ok!\n", PORT);
/* Send File to Server */
//if(!fork())
//{
char* fs_name = "/home/aryan/Desktop/quotidiani.txt";
char sdbuf[LENGTH];
printf("[Client] Sending %s to the Server... ", fs_name);
FILE *fs = fopen(fs_name, "r");
if(fs == NULL)
{
printf("ERROR: File %s not found.\n", fs_name);
exit(1);
}
bzero(sdbuf, LENGTH);
int fs_block_sz;
while((fs_block_sz = fread(sdbuf, sizeof(char), LENGTH, fs)) > 0)
{
if(send(sockfd, sdbuf, fs_block_sz, 0) < 0)
{
fprintf(stderr, "ERROR: Failed to send file %s. (errno = %d)\n", fs_name, errno);
break;
}
bzero(sdbuf, LENGTH);
}
printf("Ok File %s from Client was Sent!\n", fs_name);
//}
/* Receive File from Server */
printf("[Client] Receiveing file from Server and saving it as final.txt...");
char* fr_name = "/home/aryan/Desktop/progetto/final.txt";
FILE *fr = fopen(fr_name, "a");
if(fr == NULL)
printf("File %s Cannot be opened.\n", fr_name);
else
{
bzero(revbuf, LENGTH);
int fr_block_sz = 0;
while((fr_block_sz = recv(sockfd, revbuf, LENGTH, 0)) > 0)
{
int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr);
if(write_sz < fr_block_sz)
{
error("File write failed.\n");
}
bzero(revbuf, LENGTH);
if (fr_block_sz == 0 || fr_block_sz != 512)
{
break;
}
}
if(fr_block_sz < 0)
{
if (errno == EAGAIN)
{
printf("recv() timed out.\n");
}
else
{
fprintf(stderr, "recv() failed due to errno = %d\n", errno);
}
}
printf("Ok received from server!\n");
fclose(fr);
}
close (sockfd);
printf("[Client] Connection lost.\n");
return (0);
}
server.c
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <signal.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <netdb.h>
#define PORT 20000
#define BACKLOG 5
#define LENGTH 512
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main ()
{
/* Defining Variables */
int sockfd;
int nsockfd;
int num;
int sin_size;
struct sockaddr_in addr_local; /* client addr */
struct sockaddr_in addr_remote; /* server addr */
char revbuf[LENGTH]; // Receiver buffer
/* Get the Socket file descriptor */
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
{
fprintf(stderr, "ERROR: Failed to obtain Socket Descriptor. (errno = %d)\n", errno);
exit(1);
}
else
printf("[Server] Obtaining socket descriptor successfully.\n");
/* Fill the client socket address struct */
addr_local.sin_family = AF_INET; // Protocol Family
addr_local.sin_port = htons(PORT); // Port number
addr_local.sin_addr.s_addr = INADDR_ANY; // AutoFill local address
bzero(&(addr_local.sin_zero), 8); // Flush the rest of struct
/* Bind a special Port */
if( bind(sockfd, (struct sockaddr*)&addr_local, sizeof(struct sockaddr)) == -1 )
{
fprintf(stderr, "ERROR: Failed to bind Port. (errno = %d)\n", errno);
exit(1);
}
else
printf("[Server] Binded tcp port %d in addr 127.0.0.1 sucessfully.\n",PORT);
/* Listen remote connect/calling */
if(listen(sockfd,BACKLOG) == -1)
{
fprintf(stderr, "ERROR: Failed to listen Port. (errno = %d)\n", errno);
exit(1);
}
else
printf ("[Server] Listening the port %d successfully.\n", PORT);
int success = 0;
while(success == 0)
{
sin_size = sizeof(struct sockaddr_in);
/* Wait a connection, and obtain a new socket file despriptor for single connection */
if ((nsockfd = accept(sockfd, (struct sockaddr *)&addr_remote, &sin_size)) == -1)
{
fprintf(stderr, "ERROR: Obtaining new Socket Despcritor. (errno = %d)\n", errno);
exit(1);
}
else
printf("[Server] Server has got connected from %s.\n", inet_ntoa(addr_remote.sin_addr));
/*Receive File from Client */
char* fr_name = "/home/aryan/Desktop/receive.txt";
FILE *fr = fopen(fr_name, "a");
if(fr == NULL)
printf("File %s Cannot be opened file on server.\n", fr_name);
else
{
bzero(revbuf, LENGTH);
int fr_block_sz = 0;
while((fr_block_sz = recv(nsockfd, revbuf, LENGTH, 0)) > 0)
{
int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr);
if(write_sz < fr_block_sz)
{
error("File write failed on server.\n");
}
bzero(revbuf, LENGTH);
if (fr_block_sz == 0 || fr_block_sz != 512)
{
break;
}
}
if(fr_block_sz < 0)
{
if (errno == EAGAIN)
{
printf("recv() timed out.\n");
}
else
{
fprintf(stderr, "recv() failed due to errno = %d\n", errno);
exit(1);
}
}
printf("Ok received from client!\n");
fclose(fr);
}
/* Call the Script */
system("cd ; chmod +x script.sh ; ./script.sh");
/* Send File to Client */
//if(!fork())
//{
char* fs_name = "/home/aryan/Desktop/output.txt";
char sdbuf[LENGTH]; // Send buffer
printf("[Server] Sending %s to the Client...", fs_name);
FILE *fs = fopen(fs_name, "r");
if(fs == NULL)
{
fprintf(stderr, "ERROR: File %s not found on server. (errno = %d)\n", fs_name, errno);
exit(1);
}
bzero(sdbuf, LENGTH);
int fs_block_sz;
while((fs_block_sz = fread(sdbuf, sizeof(char), LENGTH, fs))>0)
{
if(send(nsockfd, sdbuf, fs_block_sz, 0) < 0)
{
fprintf(stderr, "ERROR: Failed to send file %s. (errno = %d)\n", fs_name, errno);
exit(1);
}
bzero(sdbuf, LENGTH);
}
printf("Ok sent to client!\n");
success = 1;
close(nsockfd);
printf("[Server] Connection with Client closed. Server will wait now...\n");
while(waitpid(-1, NULL, WNOHANG) > 0);
//}
}
}
Some comments in no particular order:
You're passing up the opportunity to know exact errors too often:
if(listen(sockfd,BACKLOG) == -1)
{
printf("ERROR: Failed to listen Port %d.\n", PORT);
return (0);
}
This block should definitely include a perror("listen") or something similar. Always include perror() or strerror() in every error handling block when the error details will be reported via errno. Having exact failure reasons will save you hours when programming and will save you and your users hours when things don't work as expected in the future.
Your error handling needs some further standardizing:
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
{
printf("ERROR: Failed to obtain Socket Descriptor.\n");
return (0);
}
This should not return 0 because that will signal to the shell that the program ran to completion without error. You should return 1 (or use EXIT_SUCCESS and EXIT_FAILURE) to signal an abnormal exit.
else
printf("[Server] Server has got connected from %s.\n", inet_ntoa(addr_remote.sin_addr));
/*Receive File from Client */
In this preceding block you've gotten an error condition but continue executing anyway. That's a quick way to get very undesirable behavior. This should either re-start the main server loop or exit the child process or something similar. (Depends if you keep the multi-process server.)
if(!fork())
{
The preceding block forgot to account for fork() failing. fork() can, and does fail -- especially in shared hosting environments common at universities -- so you should be prepared for the full, complicated three possible return values from fork(): failure, child, parent.
It appears you're using fork() indiscriminately; your client and server are both very simple and the way they are designed to run means they cannot be used to service multiple clients simultaneously. You should probably stick to exactly one process for each, at least until the algorithm is perfectly debugged and you figure out some way to run multiple clients simultaneously. I expect this is the source of the problem you're encountering now.
You need to use functions to encapsulate details; write a function to connect to the server, a function to send the file, a function to write the file, etc. Write a function to handle the complicated partial writes. (I especially recommend stealing the writen function from the Advanced Programming in the Unix Environment book's source code. File lib/writen.c.) If you write the functions correctly you can re-use them in both the client and server. (Something like placing them in utils.c and compiling the programs like gcc -o server server.c utils.c.)
Having smaller functions that each do one thing will allow you to focus on smaller amounts of code at a time and write little tests for each that will help you narrow down which sections of code still need improvement.
One discussion point seems was missing here, So I thought to mention it here.
Let us very quicky understand TCP's data transfer. There are three steps
a)Connection Establishment, b)Data Transfer, c)Connection Termination
Now here a client is sending a file to a server, over a TCP socket.
The server does some processing on the file and sends it back to the client.
Now all the 3 steps need to done. Connection Establishment is done by calling connect.
Data reading/writing is done by recv/send here and connection termination is done by close.
The server here is reading data in a loop using recv.
Now when the loop will come to an end? When the recv returns 0 or may be less than 0 on error.
When recv returns 0? -> When the other side has closed the connection.
(When the TCP FIN segement has been recived by this side).
So in this code when the client has finished sending the file,I have used a shutdown function, which sends the FIN segement from the client side and the server's recv can now return 0 and the program continues.(Half way close, since the client also needs to read data subsequently).
(Just for understanding please note TCP's connection Establisment is a 3 way Handshake and
connection termination is a 4 way handshake.)
Similarly if you forget closing the connection socket on the server side, the client's recv will also block for ever.
I think that was the reason for using ctrl c to stop the client sometimes which you have mentioned.
You may pl. refer any standard Networking book or the rfc http://www.ietf.org/rfc/rfc793.txt for learning more about TCP
I have pasted the modified code and also little added some comments,
Hope this explanation will help.
Modified client code:
while((fs_block_sz = fread(sdbuf, sizeof(char), LENGTH, fs)) > 0)
{
if(send(sockfd, sdbuf, fs_block_sz, 0) < 0)
{
fprintf(stderr, "ERROR: Failed to send file %s. (errno = %d)\n", fs_name, errno);
exit(1);
}
bzero(sdbuf, LENGTH);
}
/*Now we have sent the File's data, what about server's recv?
Recv is blocked and waiting for data to arrive or if the protocol
stack receives a TCP FIN segment ..then the recv will return 0 and
the server code can continue */
/*Sending the TCP FIN segment by shutdown and this is half way
close, since the client also needs to read data subsequently*/
shutdown(sockfd, SHUT_WR);
printf("Ok File %s from Client was Sent!\n", fs_name);
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).