request/reply server using select(). Can't write back to client - c++

I got all of this code from the beej guide so all of the accepting can be seen from there. In the Beej's code, he gets a message from a client, and then sends the message to all the other clients. This can be seen from this snippet here:
// handle data from a client
if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0) {
// got error or connection closed by client
if (nbytes == 0) {
//handle error
}
}
else {
// we got some data from a client
for(j = 0; j <= fdmax; j++) {
// send to everyone!
if (FD_ISSET(j, &master)) {
// except the listener and ourselves
if (j != listener && j != i) {
if (send(j, buf, nbytes, 0) == -1) {
perror("send");
}
}
}
}
}
} // END handle data from client
Instead of sending the same message to all the clients, i would like to adapt it into a request/reply feature and send a reply to the same client I received data from.
here is what I have so far:
long length = 0;
string stringRead;
messagebroker broker;
read( i, &length, sizeof( length ) );
length = ntohl( length );
if(length > -1)
while ( 0 < length ) {
char buffer[1024];
int cread;
cread = read( i, buffer, min( sizeof( buffer ), length ) );
stringRead.append( buffer, cread );
length -= cread;
}
cout << "Got Message: " + stringRead << endl;
string response = broker.handleMessage(stringRead.c_str());
cout << "sending response" << response << endl;
//socket ready for writing
if (FD_ISSET(i, &master)) { //should i check to see if write_fds? I have this here
//simply because the guide has it, but i am suspicious
//it is there so we can not write to the master.
length = htonl( response.length() );
cout << "sent length" << endl;
if(send( i, &length, sizeof(length) , 0) == 0){
fprintf(stderr, "Error sending data %d\n", errno);
exit(3);
}
if(send( i, response.data(), response.length(),0 )== 0){
fprintf(stderr, "Error sending data %d\n", errno);
exit(3);
}
} //end if
I receive all data from the client at the server. I then am not sure if the problem is writing the data back on the server, or reading from the client. I assume it is writing to the client from the server. As I hinted in the comments, I think I know where I went wrong, but I have removed this if statement, and I still wasn't able to read anything on the client side. Do I need to set a writable flag at the very beginning? Please let me know if you need anything else. Sorry this post was so long.

Just do the write. If it returns -1/EWOULDBLOCK, or a value indicating that it didn't write the full response, then you add the FD to the writefds, and continue the write when the FD becomes writable. You normally don't have any writefds, as FDs are normally writable, that is to say they normally have space in their socket send buffers.

Related

C++file transfer with TCP protocol

I'm currently writing a server and client app that attempts to transfer a screenshot but it's not working properly. I implemented it like this:
SOCKET sock;
char buf[4096];
DWORD WINAPI thread_function()
{
bool file_transfer = false;
bool loop = true;
while (1)
{
ZeroMemory(buf, 4096);
int bytesReceived = recv(sock, buf, 4096, 0);
if (bytesReceived > 0)
{
std::string received(buf, 0, bytesReceived);
if (received == "Sending file.")
{
file_transfer = true;
}
if (file_transfer == false)
{
std::cout << "\nSERVER> " << std::string(buf, 0, bytesReceived) << std::endl;
std::cout << "> ";
}
else if (file_transfer == true)
{
loop = true;
TCHAR *szfname = "screenshot.bmp";
FILE* f = fopen(szfname, "wb");
if (NULL == f)
{
std::cerr << "Error opening file" << std::endl;
return 1;
}
while ((bytesReceived = recv(sock, buf, 4096, 0)) > 0 && loop == true)
{
received = buf;
if (received == "File transfer completed !")
{
loop = false;
std::cout << "File transfer completed !" << std::endl;
std::cout << "> ";
}
else
{
fwrite(buf, 1, bytesReceived, f);
}
}
file_transfer = false;
}
}
}
}
I call the function with this
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)thread_function, 0, 0, 0);
The thing is I believe this is not a very clean way of doing it and also it's not working perfectly. After a file is received I don't correctly receive what the server is sending.
This is the server code which I think is fine.
send(clientSocket, TEXT("Attempting to take a screenshot."), sizeof(TEXT("Attempting to take a screenshot...")), 0);
HWND win = GetDesktopWindow();
HDC dc = GetDC(win);
if (HDCToFile("screenshot.bmp", dc, { 0, 0, 1920, 1080 }) == true)
{
send(clientSocket, TEXT("Sending file."), sizeof(TEXT("Sending file.")), 0);
FILE *fp = fopen("screenshot.bmp", "rb");
if (fp == NULL)
{
std::cerr << "Error : Cannot open file." << std::endl;
return 1;
}
while (1)
{
char buff[4096] = { 0 };
int nread = fread(buff, 1, 4096, fp);
if (nread > 0)
{
send(clientSocket, buff, sizeof(buff), 0);
}
if (nread < 4096)
{
if (feof(fp))
{
std::cout << "File transfer completed !" << std::endl;
send(clientSocket, TEXT("File transfer completed !"), sizeof(TEXT("File transfer completed !")), 0);
}
if (ferror(fp))
std::cerr << "Error reading." << std::endl;
break;
}
}
}
else
{
send(clientSocket, TEXT("Screen capture failed...."), sizeof(TEXT("Screen capture failed....")), 0);
}
Thanks for your time and help.
TCP is a streaming protocol. It has no concept of messages, so when the server sends "Sending file." there is no separation between the string and the beginning of the file being sent. Everything just goes into the stream one byte after the next and when the network stack decides it's time, usually because a packet has been filled or it's been too long since data was last added, a packet is sent, possibly containing multiple messages.
So
int bytesReceived = recv(sock, buf, 4096, 0);
very likely reads the full 4096 bytes, Attempting to take a screenshot.\0Sending file.\0 plus the first four thousand-or-so bytes of the bitmap. The client code consumes the string and discards the rest of the buffer.
You need to establish a communication protocol that sits between the the socket and the writing of the file. There are a whole bunch of different ways to handle this. Common tricks for reading strings are
Write the length of the string before writing the string so that the protocol handler knows how many bytes to read ahead of the time
Sender
uint16_t len = str.length(); // size is exactly 16 bits
len = htons(len); // endian is known
int sent = send(sock, (char*)&len, sizeof(len), 0);
// test sent for success (did not fail, sent all the bytes)
sent = send(sock, str.c_str(), len, 0);
// test sent for success (did not fail, sent all the bytes)
// may need to loop here if the string is super long.
Receiver
uint16_t len;
int recd = recv(sock, (char*)&len, sizeof(len), MSG_WAITALL);
// test recd for success (did not fail, read all the bytes)
// MSG_WAITALL will read exactly the right number of bytes or die trying.
len = ntohs(len); // ensure correct endian
std::string msg(len, ' '); // allocate a big enough string
char * msgp = &msg[0]; // or msg.data() if C++17 or better.
// Never seen &msg[0] fail, but this is not guaranteed by C++
while (len) // sometimes you want an extra exit condition here to bail out early
{
recd = recv(sock, msgp, len, 0);
// test recd for success
len -= recd;
msgp += recd;
}
Insert a canary value so that the protocol handler knows when to stop reading. The null terminator works well here. The protocol reads up until it finds the null and preserves the remainder of what's read for later consumption. No code example here because this can be done many, many different ways.
Not using strings and sending integer code messages instead. Eg:
enum messageID
{
TAKING_SCREENSHOT,
SENDING_FILE,
EATING_COOOOOOKIE_OM_NOM_NOM
};
OK! That moves the strings correctly. Assuming I don't have a bug in there. The idea's right, but the actual code is from memory and may contain brainfarts.
What you want to have is a bunch of functions, one for each type of data you send. Each of these functions can and should be be tested separately so that when you get to integrating them into the program, the program looks something like
sendString(sock, "Attempting to take a screenshot.");
if (getBitmap("screenshot.bmp"))
{
sendString(sock, "Sending file.");
sendBitmap(sock, "screenshot.bmp");
}
or
receiveString(sock);
std::string command = receiveString(sock);
if (command == "Sending file.")
{
receiveBitmap(sock, "screenshot.bmp");
}
else if (command == "Eating coooooookie! Om! Nom! Nom!")
{
OmNomNom(sock);
}
Which is about a close to foolproof as you can get.
Notes:
There is a bug in the server: int nread = fread(buff, 1, 4096, fp); gets the number of bytes read, but send(clientSocket, buff, sizeof(buff), 0); always tries to send a full buffer regardless of how many bytes were read, so garbage will be sent to the client. Also send can fail and this is not being checked. Always check the return codes. People don't put them there unless they're important.

Client-Server echo program going into deadlock in UDP

The following is the client-side code for a UDP client-server echo program :
ret_val = sendmmsg(socket_id, msgs, no_of_packets, 0);
//I send message to the server
if(ret_val == -1)
std::cerr << "Message sending failed.\n";
else{
cout << ret_val << " messages sent\n";
/************************************************************************/
char buffers[no_of_packets][packet_size + 1];
msgs = new struct mmsghdr[no_of_packets];
iovecs = new struct iovec[no_of_packets];
memset(msgs, 0, sizeof(msgs));
memset(iovecs, 0, sizeof(iovecs));
for(int i = 0;i < no_of_packets;i++){
iovecs[i].iov_base = buffers[i];
iovecs[i].iov_len = packet_size;
msgs[i].msg_hdr.msg_iov = &iovecs[i];
msgs[i].msg_hdr.msg_iovlen = 1;
}
//and receive the packet here, but the program hangs here
ret_val = recvmmsg(socket_id, msgs, no_of_packets, 0, NULL);
My program hangs here, any idea why it's happening ? The following is the server-side code which first receives and then sends successfully, but after the server sends for the first time, my client isn't able to read it as it hangs.
ret_val = recvmmsg(socket_id, msgs, no_of_packets, 0, NULL);
if(ret_val < 0){
break;
}
else{
cout << ret_val << " messages received\n";
for(int i = 0;i < ret_val;i++){
buffers[i][msgs[i].msg_len] = 0;
printf("Trip %d : %s\n", trip, buffers[i]);
}
/************************************************************************/
if(connect(socket_id, (struct sockaddr *) &server_addr, sizeof(server_addr)) == -1){
perror("connect()");
exit(EXIT_FAILURE);
}
ret_val = sendmmsg(socket_id, msgs, no_of_packets, 0);
//This send is successful, but since my client hangs,
//the server hangs as well since the 'recvmmsg' at the top gets nothing from the client
if(ret_val == -1)
std::cerr << "Message sending failed.\n";
else
cout << ret_val << " messages sent\n";
This line in the server code looks suspicious:
if(connect(socket_id, (struct sockaddr *) &server_addr, sizeof(server_addr)) == -1)
What is server_addr? It's certainly not the source address of any of the packets return from the prior call to recvmmsg.
Just remove the connect call.
I could write more, but is there any particular reason you are using recvmmsg and sendmmsg instead of recvfrom and sendto ?
Below is a much simpler way of implementing an echo server with a udp socket:
const int MAX_UDP_MESSAGE_SIZE = 65535
unsigned char message[MAX_UDP_MESSAGE_SIZE+1];
int rcvReslt, sndResult;
sockaddr_in addr = {};
socklen_t addrLength = sizeof(addr);
rcvResult = recvfrom(socket_id, message, MAX_UDP_MESSAGE_SIZE, 0, (sockaddr*)&addr, &addrLength);
if (rcvResult > 0)
{
message[rcvResult] = 0; // null terminate the message
printf("Trip %d : %s\n", trip, message);
// echo back
sndResult = sendto(socket_id, message, rcvResult, 0, (sockaddr*)&addr, addrLength);
}
else
{
int error_code = errno;
printf("Error: %d\n", error_code);
}
Clearly you're connected to the wrong target. You don't need to connect at all. recvfrommsg() both return the source IP:port. Just send back to the same place.

Sockets workflow in FTP imitation

I am trying to implement client-server communication via sockets. The main tasks are:
Sending commands from clients to server
Sending data from server to clients
Sending data from clients to server
Commands should come via port1, data via port2.
I got it working without without multi-threading but I have some problems with understanding how do I need to handle sockets.
Current scenario:
1.Server starts (socket, bind, listen for both command and info sockets) and goes for infinite loop with this function:
void FTPServer::waitForConnection()
{
sockaddr_in client;
int clientsize = sizeof(client);
SOCKET clientSocket = accept(_infoSocket, (struct sockaddr*)&client, &clientsize);
if (clientSocket == INVALID_SOCKET)
{
cout << " Accept Info Error" << endl;
}
else
{
cout << " Accept Info OK" << endl;
char* buff = new char[CHUNK_SIZE];
string fullRequest;
int rc = recv(clientSocket, buff, CHUNK_SIZE, 0);
if (rc == SOCKET_ERROR)
{
cout << " Recieve Info Error" << endl;
}
else
{
buff[rc] = NULL;
fullRequest.append(buff);
cout << " Recieve Info OK" <<endl;
if (executeCommand(fullRequest, clientSocket))
{
logOperation(client, fullRequest.c_str());
}
}
delete buff;
}
}
2.Client starts (socket, connect), creates 2 sockets on same ports, waits for user input.
3.User types "LIST", clients checks that it's a valid command and sends it.
bool FTPClient::sendToServer(string data, const bool verbose)
{
int n = 0;
while (data.size() > CHUNK_SIZE)
{
string s = data.substr(CHUNK_SIZE).c_str();
n += send(_infoSocket, data.substr(CHUNK_SIZE).c_str(), CHUNK_SIZE, 0);
data = data.substr(CHUNK_SIZE+1);
}
n+=send(_infoSocket, data.c_str(), data.size(), 0);
cout<<n<<endl;
if(n<0)
{
cout<<"Error: sending"<<endl;
return 0;
}
if (verbose)
cout<<"Send "<<n<<" bytes"<<endl;
return true;
}
4.Servers receives it, accepts on _dataSocket and sends the list of available files.
5.Client receives the list:
string FTPClient::getDataFromServer(const bool verbose)
{
char data[CHUNK_SIZE];
int size = recv(_dataSocket, data, strlen(data), 0);
if (size > 0)
{
int n = 0;
string res;
while (size > CHUNK_SIZE)
{
int buff = recv(_dataSocket, data, CHUNK_SIZE, 0);
res.append(data);
size -= buff;
n += buff;
}
n+= recv(_dataSocket, data, CHUNK_SIZE, 0);
res.append(data);
if (verbose)
cout<<"Recevied "<<n<<" bytes"<<endl;
res.resize(n);
return res;
}
else
{
return "";
}
}
Till this, it works. But if try to execute same command again, I got nothing.
I think, problem is that for each connect we need an accept on server side.
In main loop server gets only one connect from client. Is closing client command socket and reconnecting it on every request only option here? Any other advices (except for "Google it") are highly appreciated.

Select - a few questions

I have a few questions about select function, i wrote this code:
void TCPSerwer::sel()
{
struct timeval tv = {1, 0};
fd_set temp_list = m_RecvList;
//if(select(m_fdmax + 1, &temp_list, NULL, NULL, &tv) == SOCKET_ERROR)
if(select(0, &temp_list, NULL, NULL, &tv) == SOCKET_ERROR)
{
perror( "select" );
exit( 1 );
}
for(int i = 0; i <= m_fdmax; i++ )
{
if(FD_ISSET(i, &temp_list))
{
// New connection
if(i == m_ListenSocket)
{
acceptClient();
}
// Data from client
else
{
PacketHeader header;
int nbytes = recv(i, (char*)(&header), sizeof(PacketHeader),
// Error
if(nbytes < 0)
{
disconnectClient(i);
}
// success
else
{
std::cout << "type: " << header.type << " len: " << header.length << std::endl;
}
}
}
}
}
I can give first arg to select function and i can don't do that, but why ? Why a should give first arg to select ? m_fdmax is highest number of socket, but this code working without this arg.
Next question is, why select need timeout ? When i don't give this arg select marks all socket as socket that can be readable but select doing this when socket haven't any data to read. When i give this arg i don't have this problem. But why ?
if m_fdmax is highest number of socket, i have to find next highest number of socket when i close connection, Right ? And i should doing this that:
int size = m_ClientVector.size();
for(int i = 0; i < size; i++)
{
if(m_ClientVector[i] > m_fdmax)
m_fdmax = m_ClientVector[i];
}
I can give first arg to select function and i can don't do that, but why ? Why a should give first arg to select ? m_fdmax is highest number of socket, but this code working without this arg.
Read the documentation. The select() function on Windows ignores the first parameter, so it does not matter what you pass to it.
Next question is, why select need timeout ?
It does not NEED a timeout, but you can OPTIONALLY provide a timeout if desired. This way, if the requested socket state is not reached before the timeout elapses, select() can still exit and not deadlock the calling thread indefinitely, allowing it to do other things.
When i don't give this arg select marks all socket as socket that can be readable but select doing this when socket haven't any data to read.
If you do not provide a timeout, select() waits indefinitely until the requested socket state actually occurs. A socket can be marked as readable if it has data to read, but it can also be marked as readible if it has been gracefully disconnected by the other party. A subsequent call to recv() will tell you which is the case (recv() returns -1 on error, 0 on disconnect, an >0 on data). Again, read the documentation.
if m_fdmax is highest number of socket, i have to find next highest number of socket when i close connection, Right ?
If you want to calculate the highest socket number (which Windows does not care about, but other platforms do), then you would have to re-calculate the highest socket number every time you call select(), or at least whenever you re-prepare the fd_set structure (which you need to do every time you call select() anyway).
And i should doing this that
On Windows, no. On other platforms, yes.
With that said, try this code on Windows instead:
void TCPSerwer::sel()
{
struct timeval tv = {1, 0};
fd_set temp_list = m_RecvList;
int ret = select(0, &temp_list, NULL, NULL, &tv);
if (ret == SOCKET_ERROR)
{
perror( "select" );
exit( 1 );
}
if (ret == 0) // timeout
return;
for(u_int i = 0; i < temp_list.fd_count; ++i)
{
SOCKET s = temp_list.fd_array[i];
// New connection
if (s == m_ListenSocket)
{
acceptClient();
continue;
}
// Data from client
PacketHeader header;
char *pheader = (char*) &header;
int nbytes = 0;
do
{
ret = recv(s, pheader, sizeof(PacketHeader)-nbytes, 0);
// success
if (ret > 0)
nbytes += ret;
}
while ((ret > 0) && (nbytes < sizeof(PacktHeader)));
// Error or disconnect
if (nbytes < sizeof(PacktHeader))
{
disconnectClient(i);
continue;
}
// success
std::cout << "type: " << header.type << " len: " << header.length << std::endl;
}
}
About the timeout:
select can use a struct timeval to timeout. If you pass a NULL pointer, select will wait until an event comes. If you pass an address to a struct timeval, select will return even if there's not event (in your code, select will return every second).
About the fdmax: Yes you have to find the highest socket, and your snippet is correct.
Other: You don't have any FD_SET in your code. Usually, the sockets are setted (via FD_SET so) in the loop which find the highest socket.
EDIT: My bad I didn't seen the fd_set temp_list = m_RecvList; in your code. We will need more code in order to analyze your problem with select.
Thanks for help, I want use this code on Windows and Linux, and now I doing that:
When I have a new connection:
bool TCPSerwer::acceptClient()
{
SOCKET new_client = accept(m_ListenSocket, 0, 0);
if(new_client == INVALID_SOCKET)
return false;
m_ClientVector.push_back(new_client);
// Add to FD
FD_SET(new_client, &m_RecvList);
if(new_client > m_fdmax)
m_fdmax = new_client;
return true;
}
When i want to close connection:
void TCPSerwer::disconnectClient(const SOCKET& client)
{
int size = m_ClientVector.size();
for(int i = 0; i < size; i++)
{
if(m_ClientVector[i] == client)
{
closesocket(m_ClientVector[i]);
// Delete from FD
FD_CLR(m_ClientVector[i], &m_RecvList);
m_ClientVector.erase(m_ClientVector.begin() + i);
break;
}
}
// re-calculateing the highest socket number
size = m_ClientVector.size();
for(int i = 0; i < size; i++)
{
if(m_ClientVector[i] > m_fdmax)
m_fdmax = m_ClientVector[i];
}
}
I havr one question to you Remy Lebeau, your recv function look that:
recv(s, pheader, sizeof(PacketHeader)-nbytes, 0);
but recv save data at the being of bufor ? Meybe this should look that:
recv(s, pheader + nbytes, sizeof(PacketHeader)-nbytes, 0);

My http server in c++ is not sending all files back correctly

I'm working on an HTTP server in c++, and right now it works for requests of text files, but when trying to get a jpeg or something, only part of the file gets sent. The problem seems to be that when I use fgets(buffer, 2000, returned_file) it seems to increment the file position indicator much more than it actually ends up putting into the buffer. Why would this happen? I put all my code below. The problem occurs in while(true) loop that occurs when the response code is 200. Thank you to anyone who replies.
// Interpret the command line arguments
unsigned short port = 8080;
if ( (argc != 1) && (argc != 3) && (argc != 5) ) {
cerr << "Usage: " << argv[0];
cerr << " -p <port number> -d <base directory>" << endl;
return 1;
}
else {
for (int i = 1; i < argc; ++i) {
if (strcmp(argv[i], "-p") == 0)
port = (unsigned short) atoi(argv[++i]);
else if (strcmp(argv[i], "-d") == 0)
base_directory = argv[++i];
}
}
// if base_directory was not given, set it to current working directory
if ( !base_directory ) {
base_directory = getcwd(base_directory, 100);
}
// Create TCP socket
int tcp_sock = socket(AF_INET, SOCK_STREAM, 0);
if (tcp_sock < 0) {
cerr << "Unable to create TCP socket." << endl;
return 2;
}
// Create server socket
sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons( port );
server.sin_addr.s_addr = INADDR_ANY;
// Bind the socket
if (bind(tcp_sock, (sockaddr*)&server, sizeof(server)) < 0) {
cerr << "Unable to bind TCP socket." << endl;
return 3;
}
// Listen for a connection request on TCP port
listen(tcp_sock, 5);
// Create HTTP_Request object and start a while loop of accepting connections
char buffer[2000];
int bytes_recv = 0;
int recv_len = 0;
string error_reply;
HTTP_Response* response;
while (true) {
int acc_tcp_sock = accept(tcp_sock, NULL, NULL);
if (acc_tcp_sock == -1) {
cerr << "Unable to open TCP connection with client." << endl;
}
do {
// may want to do just one recv
recv_len = recv( acc_tcp_sock, buffer + bytes_recv,
2000 - bytes_recv, 0 );
bytes_recv += recv_len;
} while (false);
bytes_recv = 0;
// may want to see if this causes a memory leak
HTTP_Request* request = HTTP_Request::Parse(buffer, 2000);
response = handle_request(request); // function to handle the request
// Put response header into buffer
response->Print( buffer, 2000 );
// if 200 and GET then send header with file
if ( response->Get_code() == 200 ) {
// send response header
if ( send( acc_tcp_sock, buffer, strlen(buffer), 0 ) < 0 ) {
cerr << "Unable to send response header to client." << endl;
}
if ( method == "GET" ) {
// send file
while ( true ) {
fgets( buffer, 2000, returned_file );
if ( feof( returned_file ) ) break;
if ( send( acc_tcp_sock, buffer, strlen(buffer), 0 ) < 0 ) {
cerr << "Unable to send file in response to client." << endl;
}
}
}
fclose( returned_file ); // close file
}
else {
if ( method == "GET" ) {
error_reply = buffer + error_page;
if ( send( acc_tcp_sock, error_reply.c_str(), error_reply.length(), 0 ) < 0 ) {
cerr << "Unable to send response to client." << endl;
}
}
else {
if ( send( acc_tcp_sock, buffer, strlen(buffer), 0 ) < 0 ) {
cerr << "Unable to send respone header to client." << endl;
}
}
}
close( acc_tcp_sock ); // close the connection
}
return 0;
Don't use fgets() to read binary data that needs to survive bit-for-bit. You don't want record-separator translation, and some systems may assume it's text if you read it that way. For that matter, newlines and record-separators are completely meaningless so the fgets()` function of scanning for them is at best a confusing inefficiency and at worst simply not-binary-capable at all.
Use fread(3), or better yet, use the raw system call (Posix API anyway, on non-Unix) read(2). This will read a certain amount of bit-for-bit data and tell you how much it read. (Regarding which binary-capable API to use: normally, we are advised to buffer data because we typically process it in small units like lines. However, when moving an entire file from one place to another buffering just slows you down. In this case it is simpler and faster to just use read().)
You also can't strlen() binary data. You have to just use the byte count from the API call.
Wouldn't using strlen break on binary files?
send( acc_tcp_sock, buffer, strlen(buffer), 0 )
It is very probable that your binary files contain NULL bytes ('\0'). When you read data with fgets, it may be placed into buffer, but when you transmit it everything after \0 gets lost (your strlen call ensures this).
So, you need to use fread to read data. It returns a number of bytes that were actually read, so you don't need to use strlen at all. And don't forget to open file in binary mode!
Better, read about mapping files to memory, that way you don't have to manage buffers for reading file content, and you can pass that buffer to send and you get file size in one way.
If you really want to read bytes from file, then you have to distinguish reading binary files (with correct mime type or application/octet-stream, storing bytes read count with buffer) and opening files as text (text/* mime-types, and you can use strlen).