Send a file to a socket
I'm trying to send a file to a particular socket using C; here's the code:
int send_file(char *filepath,int sock)
{
FILE *fp=fopen(filepath,"rb");
void *buff=malloc(2000);
int i=1;
while(i)
{
int bytes_read=fread(buff,1,2000,fp);
i=!(feof(fp));
int bytes_sent=0;
while(bytes_sent<bytes_read)
{
int n=send(sock,buff+bytes_sent,bytes_read-bytes_sent,0);
if(n==-1)
return -1; //failure
bytes_sent+=n;
}
}
fclose(fp);
free(buff);
return 0;
}
When I run this program and try to view the text file in Firefox at http://127.0.0.1:8080/ , a part of the file is cut off from the end if the file 开发者_JS百科size is over 2000 bytes. If I send a picture, only 3/4th of the picture loads (cut off from the bottom).
The function always returns 0 to the caller though. Where does the last chunk of bytes it send()s disappear? Do I need to flush some stream before returning?
Thank you
EDIT: This is a snippet from my main() function:
send_file(filepath, sock);
close(sock);
return 0;
}
There's a standard API for this! Use sendfile()
.
The kernel does the copying without context-switching into your thread, which is substantially more efficient.
You should never use feof(), it is almost always the wrong thing to do. Instead, use the return value of fread() to determine when you have read everything - so long as it is non-zero, you need to keep reading and sending. In pseudo code:
while(1) {
r = fread( ... );
if ( r == 0 ) {
break;
}
send( .. );
}
I cannot see the rest of your program but I suspect that you are exiting before closing your socket.
If your program exits before the socket is finished sending its data, the OS is not obligated to do anything with the remaining unsent data and will probably throw it out.
The code you posted looks okay to me. The feof issue may exist as Neil says, although it works fine using Microsoft's compiler. I tested it as written with a stub for the send call, and all data was "sent". It would seem to me that the error maybe lies at the receiving end. An easy test would be to simply print the file lengths that you send and read at both ends. Make sure the recv call gets all flushed data.
If you're looking at the file with a web browser, you should be sending an HTTP header before you send the actual data.
I am just guessing, but most likely, in the header, you're sending the size of the data as 2000 bytes. So, even though you're sending more than 2000 bytes, the browser isn't expecting them, and displays only the first 2000 bytes.
Also, since you're closing the connection, you should send Connection: close
header to the clients.
Are you reading all of the data that the web browser sent to you? If you're not (which is understandable, if you're not actually writing a web server), then calling close()
with unread data is provoking an abort on the TCP connection instead of a clean shutdown.
A clean shutdown waits for all outstanding data to be sent; an abort does not, which can cause that outstanding data to be lost.
For testing purposes, you should be able to fix it by putting this in at the end of the sending function (before you free buff
):
shutdown(sock, SHUT_WR); /* Send EOF to web browser */
while (recv(sock, buff, 2000, 0) > 0)
; /* Read and discard until we see the browser's EOF (or an error) */
精彩评论