After shutting down a socket in write mode, I am trying to write to the duplicated handle. I am getting broken pipe even though both of them have different file descriptors. What is wrong with my code ? or Is that expected behavior ?
int clientDupFD = dup(fileDescriptors[0]);
shutdown(fileDescriptors[0], SHUT_WR);
printf ("\n Client: Writing to shutdown(SHUT_WR) socket");
writeOk = write(clientDupFD, msgPtr="Writing message after partial shutdown!", 5);
if(writeOk == -1) {
printf("\n ERR-%s: write() failed to write msg to socket", strerror(errno));
}
else {
printf("\n Client: Message '%s' successfully written to socket", msgPtr);
}
Also, when I run this through CodeLite, complete output (last printfs) are not getting executed, why ?
Only when I try it through debugger, I can see that the "ERR-Broken pipe" printf statement was executing and the output got printed. I tried using 'fflush(stdout)' as well as 'setbuf(stdout, NULL)'. Both of them didnt work. Can anybody help ?
Once a connection's write direction has been shut down, writes can no longer take place on the connection and the implementation is free to communicate to the other end that no more data will arrive. It doesn't matter what handle you use to access the connection -- it's the same connection.
You have shutdown the FD (or more accurately the connection attached to both FDs), so consequently the write fails.
If you are trying to make a socket pair, use socketpair (or pipe).
Related
So the other day I got a relatively simple assignment, which was to build some client and some server code that in which the server received a message and returned its current system time. It wasn't hard to do, i delivered and got an easy mark.
I started thinking a bit more on it and I decided to set out and try to send the contents of specific file server --> client (server sends contents to client). While i was building the code I tested every so often locally and it worked as intended, the real problem arose when I uploaded the server code to my server (hah) running Ubuntu. Started the server, everything OK, started the client, asked for "index.html" and BAM! half the file wasn't received.
The server prints it (I made it so it printed the contents of file as it sent so I could troubleshoot with more ease).
I have been searching for a bit now and every time I find something that looks useful it ends being in a different programming language and cant find any equivalents in C.
Using sleeps in both client and server code seems to solve this, but I figure it's not good practice.
The code is a mess so I'll include what I figure is relevant, I'll also include a link tot he full code. I really meant to improve it but so got demotivated while trying to fix this that I just made it worse.
Client side
printf("Please specify the filename: ");
fgets(msg,1000,stdin); // get message from std input
if(strcmp(msg,"\n")==0) {
printf("Wrong file name or format\n");
printf("Please specify the filename: ");
fgets(msg,1000,stdin); // get message from std input
}
while(strcmp(msg,"!stop\n")) {
msg[strlen(msg)-1]='\0';
write(sockfd,msg,strlen(msg));
FILE *fp = NULL;
char filecontent[1000];
bzero(filecontent,sizeof(filecontent));
while( (n = read(sockfd,filecontent,1000)) && strcmp(filecontent,"Over and out!")!=0 ) {
if(strcmp(filecontent,"No such file")!=0 && fp == NULL) {
fp = fopen(msg,"w");
}
printf("%s",filecontent);
if(fp !=NULL)
fprintf(fp, "%s",filecontent);
bzero(filecontent,sizeof(filecontent));
}
if(fp != NULL)
fclose(fp);
printf("\nPlease specify the filename: ");
fgets(msg,1000,stdin); // get message from std input
if(strcmp(msg,"\n")==0) {
printf("Wrong file name or format\n");
printf("Please specify the filename: ");
fgets(msg,1000,stdin); // get message from std input
}
}
Server side
char date[50];
time_t ticks;
struct tm *tinfo;
time(&ticks);
tinfo=localtime(&ticks);
strcpy(date,asctime(tinfo));
printf("DATA: %s\n",date);
write(newsocketfd,date,sizeof(date));
while( (n = read(newsocketfd,msg,1000)) && strcmp(msg,"!stop\n")!=0) {
//printf("MSG: %s\n",msg);
if(n<0)
error("ERROR READING");
/////////READING FILE/////////////
char *filename = malloc(sizeof(msg)+1);
strcpy(filename,msg);
printf("'server filename:%s'\n",filename);
FILE *fp = fopen( filename,"r");
if(fp == NULL) {
printf("No such file found\n");
write(newsocketfd,"No such file",sizeof("No such file"));
}
while( fp!=NULL && fgets(msg,1000,fp)!=NULL){
write(newsocketfd,msg,sizeof(msg));
msg[strlen(msg)-1]='\0';
printf("server: '%s'\n",msg);
bzero(msg,sizeof(msg));
}
bzero(msg,sizeof(msg));
bzero(filename,strlen(filename));
n = write(newsocketfd,"Over and out!",sizeof("Over and out!"));
printf("Over\n");
}
sorry for any headaches. Full code here.
Examples:
I think this pretty much shows the problem
My thinking was, the server reads the file, line by line, and sends its, line by line, to the client, when it's done the server sends "over" and the client stops reading from there, it seems however that the client never receives all the information or the "over" signal. Worth adding that this works perfectly fine if I run both codes on my local machine.
Welcome to the world of network programming! Network protocols are layered for a reason. When you send something on a TCP socket, and immediately close the socket, the delivery is unreliable: it may be correctly delivered to the peer, or may vanish because of race conditions.
The only reliable way is to only close the socket when the peer sends an acknowledgement that it could receive everything that was sent. Standard protocol use control messages for that, and you really should contemplate that, but if you do not need your server to be warned for client failures, you could simply have the client to close the connection when it has received "Over and out!". BTW, you should be aware that as TCP is a stream protocol, nothing can guarantee that the message will not be splitted in more than one read, or concatenated to other bytes. So you should keep the end of the previous read (size of the signal string minus one byte), concatenate next read to that and search the string anywhere in the buffer.
Another common way is to use a graceful shutdown: the sender uses shutdown(socket.SHUT_WR) to signal that the communication is over without closing the socket and waits (with a read) for the peer to close the socket when everything has been correctly delivered.
I have implemented end_server() method using some volatile flag should_server_end = true/false. I have used non-blocking connection sockets to enable checking this flag between consecutive recv() calls. It works fine. But I have read about using shutdown(sock, SHUT_RDWR) called from the main thread that can stop the server (and its connections) running in the background. I would like to try this approach in my app and implement some alternative methods instead of end_server() like shutdown_server().
I have tried something like this:
int pasv_sock = server_info_sock(server_info);
if(shutdown(pasv_sock, SHUT_RDWR) < 0) {
fprintf(stderr, "shutdown: failed! %s\n", strerror(errno));
return FAILURE;
}
But now I am getting error message:
shutdown: failed! Socket is not connected
which means shutdown() return this error code:
ENOTCONN
The specified socket is not connected.
1. Can I only use shutdown on active (connection) sockets and not on passive (server) socket. Should I just use close()?
Next I change shutdown() to close() on passive socket, and then nothing happens. No errors but as in the previous method with shutdown connection still works correctly and I can send() and recv() packets of data.
2. Does it mean that close()-ing passive socket only stops possibility of making new connections with the server (server will no longer accept connections?)
So I have changed the code to something like this:
static void shutdown_conn_sock_data_handler(void *data, size_t data_size) {
sock_fd_t *conn_sock = (sock_fd_t *) data;
printf("Connection sock: %d closing...!\n", *conn_sock);
if(shutdown(*conn_sock, SHUT_RDWR) < 0) {
fprintf(stderr, "shutdown: failed! %s\n", strerror(errno));
return;
}
}
server_info_set_force_shut_down(server_info, 1);
const linked_list_t *conn_socks = server_info_conn_socks(server_info);
linked_list_travers(conn_socks, shutdown_conn_sock_data_handler);
int pasv_sock = server_info_sock(server_info);
if(close(pasv_sock) < 0) {
fprintf(stderr, "close: failed! %s\n", strerror(errno));
return FAILURE;
}
return SUCCESS;
}
It works now but this need also some flag to give the hint information about the closed server, otherwise, it will be closed with some error message as trying to accept new connections on the already closed passive socket.
So before trying to accept a new connection I need to check like this:
while(1) {
if(server_info_should_shut_down(server_info)) {
return CLOSED;
}
if(server_info_force_shut_down(server_info)) {
return FORCE_CLOSED;
}
As you can see such a force close approach doesn't differ much from lazy shutdown when I just set volatile should_shut_down flag and wait for the server to detect this and close in a regular way. The only benefit is that I possibly no longer have to have:
non-blocking connection sockets in connection_handlers (this functions are supplied by client code using server api)
before each client code need to set:
fcntl(sock_fd, F_SETFL, O_NONBLOCK);
to enable server self-closing.
*client - means programmer using server API, not client side of TCP communication.
moreover there was need to place after each recv failing without new request data
if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
// call to recv() on non-blocking socket result with nothing to receive
continue;
}
and client-code needs to add in connection_handler in between each client-side request:
if(server_info_should_shut_down(server_info))
return CLOSED;
So implementing this shutdown_server() method instead of end_server()
I can hide implementation details inside server API and allow user of this API to provide simpler and cleaner connection handler. Just recv/send logic without need to inject some special code that enables the server to be closable!
3. Is it this new approach with shutdown() correct? Didn't I missed anything?
Can I only use shutdown on active (connection) sockets and not on passive (server) socket.
Yes.
Should I just use close()?
Yes.
Next I change shutdown() to close() on passive socket, and then nothing happens. No errors but as in the previous method with shutdown connection still works correctly and I can send() and recv() packets of data.
Correct. That's how it works.
Does it mean that close()-ing passive socket only stops possibility of making new connections with the server (server will no longer accept connections?)
Yes. It doesn't affect existing accepted sockets.
Is it this new approach with shutdown() correct? Didn't I missed anything?
You should not shutdown the sockets for output. That will cause errors at both ends: this end, because it may write to a shutdown socket, and the other end because it will receive a truncation.
All you need to to is shutdown each accepted socket for input (i.e. SHUT_RD). That will cause the next recv() on that socket to return zero,meaning the peer disconneceted, whereupon the existing code should already close the socket and exit the thread.
I'm using C language to send data via socket in Linux by using command
send(ServerSocket, cSendBuff, strlen(cSendBuff), 0);
The procedure is:
Create socket
Connect to Server
while (condition): Send data
When I run this program in Linux environment, if it is connected, there is no problem. But in order to take care of failed connection when running, I check some cases and got results as below:
Case 1:
Create socket: No creation (comment out creating function)
Connection to Server: No connection (comment out connecting function)
Send data --> Failed (return -1) but no crash
Case 2:
Create socket: Successfully
Connection to Server: Failed or even No connection (comment out
connecting function)
Send data --> Crash
And then, i tried 3 different values of socket WITHOUT connection to server
Case 3:
ServerSocket = -1 --> Send data: Failed
ServerSocket = 0 --> Send data: Failed
ServerSocket = 4 --> Send data: Crash
In case of failed sending, it is correct but I don't understand why i got crash in other cases. I tried with Windows but no problem, is that a different between Linux and Windows? does it make sense? I want to open socket and connect to server only once time and after that sending data a thousand times, so if "the crash" makes sense in this case, how can I fix this problem in case of failed connection? Thanks for your time.
Here is the Case 2 (connect failed by stopping Server in order to test a case of failed connection):
ServerSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_IP) ;
...
iResult = connect(ServerSocket,(struct sockaddrx *)&server , sizeof(server));
iResult = send(ServerSocket, cSendBuff, strlen(cSendBuff), 0);
if(iResult<0)
{...}
Here is the Case 3:
//ServerSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_IP) ;
...
//iResult = connect(ServerSocket,(struct sockaddrx *)&server , sizeof(server));
ServerSocket = 0;
iResult = send(ServerSocket, cSendBuff, strlen(cSendBuff), 0);
log();
ServerSocket = -1;
iResult = send(ServerSocket, cSendBuff, strlen(cSendBuff), 0);
log();
ServerSocket = 4;
iResult = send(ServerSocket, cSendBuff, strlen(cSendBuff), 0);
log();
if(iResult<0)
{...}
Your program does not crash!
It receives a SIGPIPE signal because the local end of the socket has been shut down. Read man 2 send, especially the EPIPE error case. (So, to be precise, your program is terminated due to an unhandled SIGPIPE signal.)
As the man 7 signal man page says, the default disposition for SIGPIPE is to terminate the process. To avoid the termination, either set a SIGPIPE signal handler, or use send(socket, buffer, length, MSG_NOSIGNAL).
Do not use Windows as your measuring stick. It is not a sane method. You have much better, actually reliable documentation available. The Linux man-pages project is one of the best sources for the C library documentation (section 3). Even though it is focused on Linux and GNU C library, every page has a Conforming to section which tells you when and where that functionality is available.
The above links refer to the up-to-date web pages, but you can also use man 2 send, man 7 signal on the command line to browse the same information. The web pages are more up to date than the distributions, but the project only includes standard man pages, not those installed by applications or extra libraries you might have.
Questions?
Case 2.3: This should fail, by which I mean it should return -1 with an accompanying value of errno. You don't state what you mean by 'fail' or 'crash,' so it is impossible to comment further.
Case 3:
These should all fail ditto unless FD 0 or 4 happens to be a socket.
I have no idea why you're even testing any of this. A 'failed connection' is a completely different thing from a socket that has never been connected in the first place. A 'failed connection' manifests itself as a -1 return from send(), recv(), and friends, with an accompanying value of errno other than EAGAIN/EWOULDBLOCK. You can't send to a TCP socket that isn't connected, and it shouldn't be possible for your code to even attempt it. If it is, your error handling code path is incorrect.
I am building a server client model in C. The clients connects to the server and they start exchanging data. However, the user can end the client at any time in the program, but the server is not notified about it. The server keeps sending that data even after the client is closed.
I was in the impression that send function will return -1 if the server is unable to send the data, but my server program just stuck at send
if((byteSent = send(new_fd, fileContents, strlen(fileContents), 0)) == -1){ //
the program just halts at the above line.
How do I overcome this problem?
//Code
exitT = 0;
//execution_count = 1;
for(i=0;i<execution_count;i++)
{
sleep(time_delay);
//getting the current time on the server machine
time_t t;
time(&t);
char *time=ctime(&t);
printf("The Execution time at server = %s\n",time);
system(exec_command);
/*Open the file, get file size, read the contents and close the file*/
// Open the file
fp = fopen(fileName,"r");
// Get File Size
fseek(fp,0,SEEK_END);
dataLength = ftell(fp);
rewind(fp);
fileContents = (char*)malloc(dataLength+1);
// Read File
fread(fileContents,1,dataLength,fp);
fileContents[dataLength] = '\0';
// Close file
fclose(fp);
printf("sockfd = %d \n",new_fd);
// send file length to client
rc=send(new_fd, &dataLength, sizeof(dataLength), 0) ;
printf("length of client data = %d \n",rc);
printf("sockfd = %d \n",new_fd);
// send time to client
rc=send(new_fd, time, strlen(time), 0) ;
printf("length of client time = %d \n",rc);
usleep(20000);
// Send file contents to Client
while(dataLength>0){
printf("sockfd = %d \n",new_fd);
if((byteSent = send(new_fd, fileContents, strlen(fileContents), 0)) == -1){
printf("bytes sent = %d \n",byteSent);
exitT = 1;
break;
}
dataLength-=byteSent;
}
//Delete the log file
sprintf(deleteCommand,"rm %s",fileName);
system(deleteCommand);
if(exitT == 1)
break;
}
bzero(fileName,sizeof(fileName));
bzero(exec_command,sizeof(exec_command));
bzero(deleteCommand,sizeof(deleteCommand));
//decClientNum();
kill(parent_id,SIGALRM);
close(new_fd); // parent doesn't need this
printf("STATUS = CLOSED\n");
exit(0);
}
Thanks
I assume you are coding for a Linux or Posix system.
When a syscall like send fails it returns -1 and sets the errno; you very probably should use errno to find out why it failed.
You could use strace to find out which syscalls are done by your sever, or some other one. Of course, use also the gdb debugger.
You very probably need to multiplex inputs or outputs. The system calls doing that are poll, select (and related ppoll and pselect). Read e.g. the select_tut(2) man page.
You may want to use (or at least to study the source code of) existing event oriented libraries like libevent, libev etc.. (Both Gtk and Qt frameworks provide also their own, which might be used even outside of GUI applications).
I strongly suggest reading about advanced unix programming and unix network programing (and perhaps also about advanced linux programming).
maybe you're using a tcp protocol and the server is waiting for an ACK. Try using udp if you want your connection to be asynchronous.
From the man page: No indication of failure to deliver is implicit in a send(). Locally detected errors are indicated by a return value of -1.
Proably something like this might help: http://stefan.buettcher.org/cs/conn_closed.html
I think I am pretty late in the party, but I think this answer might help someone.
If space is not available at the sending socket to hold the message to be transmitted, and the socket file descriptor does not have O_NONBLOCK set, send() shall block until space is available.
When send() function gets stuck, there might be a situation like, TCP window size has become 0. It happens when the other end of the connection is not consuming received data.
There might be a scenario like this, the receiving end process is running by GDB and segfault occurred.
The TCP connection remains established.
Data is being send continuously.
The receiver end is not consuming it.
Consequently the receiver TCP window size will keep decreasing and you can send data till it is greater than zero. Once it becomes 0, send() function will get stuck forever.
As the situation mentioned in the question is not a scenario of closed connection. When a process writes something on a closed TCP connection, it receives a signal SIGPIPE. Default handler of SIGPIPE terminates the process. So, in a closed connection scenario if you are not using your own SIGPIPE handler then process should be terminated by default handler whenever something is written on the socket.
I implemented a client-server program that allows to transfer files b/w them. The server is using select() to check changes of sockets.
Every test is good except this one:
- When server is sending a huge file to client (not yet finished), client hit "Ctrl-C" to kill the client program, then the server is killed too :(
The snippet:
fprintf(stderr,"Reading done, sending ...\n");
if(send(sockClient, sendBuf, chunk_length, 0) < 0)
{
printf("Failed to send through socket %d \n", sockClient);
return -1;
}
fprintf(stderr,"Sending done\n");
When the client is killed, the server terminal displays:
user$./server
Reading done, sending ...
Sending done
Reading done, sending ...
Sending done
Reading done, sending ...
Sending done
Reading done, sending ...
user$
What's wrong with it?
Thanks for your answers!
You probably want to ignore SIGPIPE. Try adding something like this in your server startup:
#include <signal.h>
signal(SIGPIPE, SIG_IGN);
The send() call may be used only when the socket is in a connected state (so that the intended recipient is known). the return is the bytescount sent...
if(send(sockClient, sendBuf, chunk_length, 0) < 0)
so when disconnected, it skipped out...
MSG_NOSIGNAL is not portable and will not be available on Windows.