Read the whole file and send it via sockets - c++

I made a server and client that should transfer files.
I tried to make it read the whole file and send it.
But now as I see it, I am having a problem.
Server should automatically send the file when the client is connected.
But the file is empty, and I don't know where the problem is
You can see that I'm trying to send .txt file. But I would like in the future send a big file, but not bigger than 1MB.)
Edit:
Picture here: http://img819.imageshack.us/img819/8259/aadi.jpg
Left side: The file that I tried to send.
Right side: The file I received
The Problem: The file that I received has been damaged, and I can't use it.
Server:
#include <WinSock2.h>
#include <Windows.h>
#include <stdio.h>
#include <iostream>
using namespace std;
#pragma comment(lib, "Ws2_32.lib")
#define Port 6000
SOCKET Socket, Sub;
WSADATA Winsock;
sockaddr_in Addr;
sockaddr_in IncomingAddress;
int AddressLen = sizeof(IncomingAddress);
int main()
{
WSAStartup(MAKEWORD(2, 2), &Winsock); // Start Winsock
if(LOBYTE(Winsock.wVersion) != 2 || HIBYTE(Winsock.wVersion) != 2) // Check version
{
WSACleanup();
return 0;
}
Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
ZeroMemory(&Addr, sizeof(Addr));
Addr.sin_family = AF_INET;
Addr.sin_port = htons(Port);
bind(Socket, (sockaddr*)&Addr, sizeof(Addr));
if(listen(Socket, 1) == SOCKET_ERROR)
{
printf("listening error\n");
}
else
{
printf("listening ok\n");
}
if(Sub = accept(Socket, (sockaddr*)&IncomingAddress, &AddressLen))
{
char *ClientIP = inet_ntoa(IncomingAddress.sin_addr);
int ClientPort = ntohs(IncomingAddress.sin_port);
printf("Client conncted!\n");
printf("IP: %s:%d\n", ClientIP, ClientPort);
printf("Sending file .. \n");
FILE *File;
char *Buffer;
unsigned long Size;
File = fopen("C:\\Prog.rar", "rb");
if(!File)
{
printf("Error while readaing the file\n");
getchar();
return 0;
}
fseek(File, 0, SEEK_END);
Size = ftell(File);
fseek(File, 0, SEEK_SET);
Buffer = new char[Size];
fread(Buffer, Size, 1, File);
char cSize[MAX_PATH];
sprintf(cSize, "%i", Size);
fclose(File);
send(Sub, cSize, MAX_PATH, 0); // File size
//int len = Size;
//char *data = Buffer;
int Offset = 0;
while(Size > Offset)
{
int Amount = send(Sub, Buffer + Offset, Size - Offset, 0);
if(Amount <= 0)
{
cout << "Error: " << WSAGetLastError() << endl;
break;
}
else
{
Offset += Amount;
printf("2\n");
}
}
free(Buffer);
closesocket(Sub);
closesocket(Socket);
WSACleanup();
}
getchar();
return 0;
}
Client:
#include <WinSock2.h>
#include <Windows.h>
#include <stdio.h>
#include <iostream>
using namespace std;
#pragma comment(lib, "Ws2_32.lib")
SOCKET Socket;
WSADATA Winsock;
sockaddr_in Addr;
int Addrlen = sizeof(Addr);
int main()
{
WSAStartup(MAKEWORD(2, 2), &Winsock); // Start Winsock
if(LOBYTE(Winsock.wVersion) != 2 || HIBYTE(Winsock.wVersion) != 2) // Check version
{
WSACleanup();
return 0;
}
Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
ZeroMemory(&Addr, sizeof(Addr)); // clear the struct
Addr.sin_family = AF_INET; // set the address family
Addr.sin_addr.s_addr = inet_addr("127.0.0.1");
Addr.sin_port = htons(6000); // set the port
if(connect(Socket, (sockaddr*)&Addr, sizeof(Addr)) < 0)
{
printf("Connection failed !\n");
getchar();
return 0;
}
printf("Connection successful !\n");
printf("Receiving file .. \n");
int Size;
char *Filesize = new char[1024];
if(recv(Socket, Filesize, 1024, 0)) // File size
{
Size = atoi((const char*)Filesize);
printf("File size: %d\n", Size);
}
char *Buffer = new char[Size];
//int len = Size;
//char *data = Buffer;
int Offset = 0;
while(Size > Offset)
{
int Amount = recv(Socket, Buffer + Offset, Size - Offset, 0);
if(Amount <= 0)
{
cout << "Error: " << WSAGetLastError() << endl;
break;
}
else
{
Offset += Amount;
printf("2\n");
}
}
FILE *File;
File = fopen("Prog.rar", "wb");
fwrite(Buffer, 1, Size, File);
fclose(File);
getchar();
closesocket(Socket);
WSACleanup();
return 0;
}

The send API may not send all the data you requested to send. So, you have to pay attention to the return value, and retry the send from where the last send ended. As an example:
offset = 0;
while (offset < bufsize) {
r = send(socket, buf+offset, bufsize-offset);
if (r <= 0) break;
offset += r;
}
While you are doing something similar for your file transfer, you do not make sure this is the case for your file size.
When you send the file size, you only need to send the string that represents the size, not the entire MAX_PATH. The receiver then needs to parse the first string to determine the size, but any data read in after the end of the first string needs to be considered part of the file. However, since you are trying the send MAX_PATH, the receiver should receive the same amount. Your client code receives 1024 bytes, but there is no indication this is the same size as MAX_PATH.
The recv API may also return fewer bytes than requested. You use a loop to handle reading the file, but you may need a loop to read the entire message that contains the file size.
In your client receive loop, you are incrementing the data pointer. This makes it unusable to write out the file later. You already have Buffer though, so use that to write out your file.
fwrite(Buffer, 1, len, File);
If you encounter an error doing socket I/O, you can retrieve the error with WSAGetLastError(), or you can issue getsockopt() on the socket with the SO_ERROR option. These may return different values, but the error reason should be correlated.

Myself faced the same problem and after googling found that send() api can send a maximum data based on low level TCP buffers which are os dependent.So inorder to send a huge file we need to perform file chunking , ie send the file in the form of chunks.
`const int FILE_CHUNK_SIZE = 2000;
//get file size
ifstream file("myFile.file", ios::binary);
file.seekg(0, ios::end);
unsigned int fileSize = file.tellg();
file.close();
//get the file
char* fileBuffer = new char[fileSize];
file.open("myFile.file", ios::binary);
file.seekg (0, ios::beg);
file.read (fileBuffer, fileSize);
file.close();
//send file in chunks
unsigned int bytesSent = 0;
int bytesToSend = 0;
while(bytesSent < fileSize)
{
if(fileSize - bytesSent >= FILE_CHUNK_SIZE)
bytesToSend = FILE_CHUNK_SIZE;
else
bytesToSend = fileSize - bytesSent;
send(ConnectSocket, fileBuffer + bytesSent, bytesToSend, 0 );
bytesSent += bytesToSend;
}
delete [] fileBuffer;`
At the receiving end we need to have a recv() api called till the whole file content is read.
credits to:shacktar cplusplus.com

Related

Sending files over TCP sockets C++ | Windows [duplicate]

This question already has answers here:
C: send file to socket
(4 answers)
Closed 2 years ago.
I want to send files over TCP sockets in C++ on Windows, all is working absolutely fine, however I can't send big files like this, I understand that TCP as any protocol has it's limitations, like I can't send more than 64KB per packet, my method works for small file sizes(tested all up to 12KB), but I would like to send LARGE files, like iso image of ubuntu or windows, which are surely bigger than 12 fully packed packets and etc.
Server
int filesize = 0;
int err = recv(conn, (char*)&filesize, sizeof(filesize), 0);
if (err <= 0)
{
printf("recv: %d\n", WSAGetLastError());
clean(conn);
}
printf("recv %d bytes [OK]\n", err);
char* buffer = new char[filesize];
ZeroMemory(buffer, filesize);
err = recv(conn, buffer, filesize, MSG_WAITALL);
if (err <= 0)
{
printf("recv: %d\n", WSAGetLastError());
clean(conn);
}
printf("recv %d bytes [OK]\n", err);
ofstream file("a.txt", ios::binary);
file.write(buffer, filesize);
delete[] buffer;
file.close();
Client
ifstream file("a.txt", ios::binary);
file.seekg(0, ios::end);
int size = file.tellg();
file.seekg(0, ios::beg);
char* buffer = new char[size];
file.read(buffer, size);
file.close();
int* fsize = &size;
int err = send(client, (char*)fsize, sizeof(int), 0);
if (err <= 0)
{
printf("send: %d\n", WSAGetLastError());
}
printf("send %d bytes [OK]\n", err);
err = send(client, buffer, size, 0);
if (err <= 0)
{
printf("send: %d\n", WSAGetLastError());
}
printf("send %d bytes [OK]\n", err);
delete[] buffer;
All values for both sides are initialised, and error handling is done well, and if I had problem then I would have said about that. I decided to use MSG_WAITALL because I guess that is suitable for this case, please correct my code for recieving/sending and if possible refactor it, it would be nicer if it would be with explainations, so that evrybody could learn to code better, thanks)))
The one main point that should be taken away from the comments below your question is that send and recv are fickle. Just because you write send(buffer with 100 bytes) doesn't mean it's going to send 100 bytes. It could send 25 bytes, or 99 bytes, or fail out completely. It's up to you to take the return value and compute what needs to still be sent.
Same goes with recv. If you write recv(buffer with 100 bytes) because you are expecting 100 bytes, it could only grab 25 bytes, or 99 bytes, or fail out completely. Again, it's up to you to use that return value and compute what still needs to be received.
File I/O is completely different. If you want to write 100 bytes to a file, those 100 bytes are guaranteed to be written if the method doesn't fail. So, when folks who have worked with file I/O move to socket I/O usually end up confused why things aren't sending or receiving correctly.
One of the trickier parts to socket programming is knowing how much data you will need to receive. You covered that by sending the length of the file first. The server will know to read in that value, then continue reading until that value is satisfied.
Some protocols, like HTTP, will use delimiters (in HTTP's case \r\n\r\n) to signal when a packet of data has ended. So, as a socket programmer, you would recv on a loop until those 4 bytes are read.
I put together an example on how you could accomplish sending and receiving a large file (this will handle files up to 9,223,372,036,854,775,807 in length). This isn't pure C++, I cheated in places because of lack of time. I used some Windows-only constructs for the same reason.
So let's take a look at it:
int64_t GetFileSize(const std::string& fileName) {
// no idea how to get filesizes > 2.1 GB in a C++ kind-of way.
// I will cheat and use Microsoft's C-style file API
FILE* f;
if (fopen_s(&f, fileName.c_str(), "rb") != 0) {
return -1;
}
_fseeki64(f, 0, SEEK_END);
const int64_t len = _ftelli64(f);
fclose(f);
return len;
}
///
/// Recieves data in to buffer until bufferSize value is met
///
int RecvBuffer(SOCKET s, char* buffer, int bufferSize, int chunkSize = 4 * 1024) {
int i = 0;
while (i < bufferSize) {
const int l = recv(s, &buffer[i], __min(chunkSize, bufferSize - i), 0);
if (l < 0) { return l; } // this is an error
i += l;
}
return i;
}
///
/// Sends data in buffer until bufferSize value is met
///
int SendBuffer(SOCKET s, const char* buffer, int bufferSize, int chunkSize = 4 * 1024) {
int i = 0;
while (i < bufferSize) {
const int l = send(s, &buffer[i], __min(chunkSize, bufferSize - i), 0);
if (l < 0) { return l; } // this is an error
i += l;
}
return i;
}
//
// Sends a file
// returns size of file if success
// returns -1 if file couldn't be opened for input
// returns -2 if couldn't send file length properly
// returns -3 if file couldn't be sent properly
//
int64_t SendFile(SOCKET s, const std::string& fileName, int chunkSize = 64 * 1024) {
const int64_t fileSize = GetFileSize(fileName);
if (fileSize < 0) { return -1; }
std::ifstream file(fileName, std::ifstream::binary);
if (file.fail()) { return -1; }
if (SendBuffer(s, reinterpret_cast<const char*>(&fileSize),
sizeof(fileSize)) != sizeof(fileSize)) {
return -2;
}
char* buffer = new char[chunkSize];
bool errored = false;
int64_t i = fileSize;
while (i != 0) {
const int64_t ssize = __min(i, (int64_t)chunkSize);
if (!file.read(buffer, ssize)) { errored = true; break; }
const int l = SendBuffer(s, buffer, (int)ssize);
if (l < 0) { errored = true; break; }
i -= l;
}
delete[] buffer;
file.close();
return errored ? -3 : fileSize;
}
//
// Receives a file
// returns size of file if success
// returns -1 if file couldn't be opened for output
// returns -2 if couldn't receive file length properly
// returns -3 if couldn't receive file properly
//
int64_t RecvFile(SOCKET s, const std::string& fileName, int chunkSize = 64 * 1024) {
std::ofstream file(fileName, std::ofstream::binary);
if (file.fail()) { return -1; }
int64_t fileSize;
if (RecvBuffer(s, reinterpret_cast<char*>(&fileSize),
sizeof(fileSize)) != sizeof(fileSize)) {
return -2;
}
char* buffer = new char[chunkSize];
bool errored = false;
int64_t i = fileSize;
while (i != 0) {
const int r = RecvBuffer(s, buffer, (int)__min(i, (int64_t)chunkSize));
if ((r < 0) || !file.write(buffer, r)) { errored = true; break; }
i -= r;
}
delete[] buffer;
file.close();
return errored ? -3 : fileSize;
}
Sending and Receiving Buffers
At the top we have two methods that works with buffers in memory. You can send it any buffer at any size (stay reasonable here), and those methods will send and receive until all the bytes passed in have been transmitted.
This does what I was talking about above. It takes the buffer and loops until all the bytes have been successfully sent or received. After these methods complete, you are guaranteed that all data is transmitted (as long as the return value is zero or positive).
You can define a "chunk size" which is the default size of the chunks of data the methods will use to send or receive data. I am sure these can be optimized by using more suitable values than what they are currently set at, but I don't know what those values are. It's safe to leave them at the default. I don't think that with the speed of today's computers you will notice too much of a difference if you change it to something else.
Sending and Receiving Files
The code for doing files is almost identical in nature to the buffer code. Same idea, except now we can assume that if the return value is greater than zero from the buffer methods then it was successful. So the code is a little simpler. I use a chunk size of 64KB... for no special reason. This time the chunk size determines how much data is read from the file I/O operations, not the sockets I/O.
Test Server and Client
Just to be complete, I used this code below to test this with a 5.3 GB file I have on disk. I basically just re-wrote Microsoft's client/server examples in a very slimmed down way.
#pragma comment(lib, "Ws2_32.lib")
#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <fstream>
DWORD __stdcall ClientProc(LPVOID param) {
struct addrinfo hints = { 0 }, * result, * ptr;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
if (getaddrinfo("127.0.0.1", "9001", &hints, &result) != 0) {
return ~0;
}
SOCKET client = INVALID_SOCKET;
for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
client = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (client == SOCKET_ERROR) {
// TODO: failed (don't just return, cleanup)
}
if (connect(client, ptr->ai_addr, (int)ptr->ai_addrlen) == SOCKET_ERROR) {
closesocket(client);
client = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (client == SOCKET_ERROR) {
std::cout << "Couldn't create client socket" << std::endl;
return ~1;
}
int64_t rc = SendFile(client, "D:\\hugefiletosend.bin");
if (rc < 0) {
std::cout << "Failed to send file: " << rc << std::endl;
}
closesocket(client);
return 0;
}
int main()
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
{
struct addrinfo hints = { 0 };
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
struct addrinfo* result = NULL;
if (0 != getaddrinfo(NULL, "9001", &hints, &result)) {
// TODO: failed (don't just return, clean up)
}
SOCKET server = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (server == INVALID_SOCKET) {
// TODO: failed (don't just return, clean up)
}
if (bind(server, result->ai_addr, (int)result->ai_addrlen) == INVALID_SOCKET) {
// TODO: failed (don't just return, clean up)
}
freeaddrinfo(result);
if (listen(server, SOMAXCONN) == SOCKET_ERROR) {
// TODO: failed (don't just return, clean up)
}
// start a client on another thread
HANDLE hClientThread = CreateThread(NULL, 0, ClientProc, NULL, 0, 0);
SOCKET client = accept(server, NULL, NULL);
const int64_t rc = RecvFile(client, "D:\\thetransmittedfile.bin");
if (rc < 0) {
std::cout << "Failed to recv file: " << rc << std::endl;
}
closesocket(client);
closesocket(server);
WaitForSingleObject(hClientThread, INFINITE);
CloseHandle(hClientThread);
}
WSACleanup();
return 0;
}

Cannot send a bigger file

I made a client server program by using C++.
I have a problem if I try to send large files. For example, a 50 byte file works fine while a 200 byte file fails.
Server Code:
// server.cpp : Defines the entry point for the console application.
#include "stdafx.h"
#include <WinSock2.h>
#include <Windows.h>
#include <stdio.h>
int _tmain(int argc, _TCHAR* argv[])
{
WORD wVersionRequested;
WSADATA wsaData;
int wsaerr;
wVersionRequested = MAKEWORD(2, 2);
wsaerr = WSAStartup(wVersionRequested, &wsaData);
if (wsaerr != 0) {
printf("The Winsock DLL not found \n ");
} else {
printf("The Winsock DLL found\n ");
}
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
printf("not support Winsock version 2.2 ");
} else {
printf("support winsock version 2.2 \n ");
}
SOCKET m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_socket == INVALID_SOCKET) {
printf("Error di socket(): %ld\n", WSAGetLastError());
WSACleanup();
} else{
printf("Socket() Berhasil ! \n");
}
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("127.0.0.1");
service.sin_port = htons(55555);
int namelen = sizeof(service);
int m_bind = bind(m_socket, (sockaddr*)&service, namelen);
if (m_bind == SOCKET_ERROR){
printf("bind() failed ! %ld\n ", WSAGetLastError());
} else {
printf("bind() ok ! \n");
}
if (listen(m_socket, 1) == SOCKET_ERROR) {
printf("Listen() failed ! %d\n ", WSAGetLastError());
} else {
printf("Listen() ok ! \n");
}
SOCKET AcceptSocket;
printf("waiting for Client...\n \n");
int addresslen = sizeof(service);
while (AcceptSocket = accept(m_socket, (sockaddr*)&service, &addresslen)) {
printf("Server dan Client connected --> ");
char *ClientIP = inet_ntoa(service.sin_addr);
int ClientPort = ntohs(service.sin_port);
printf("IP: %s:%d\n ", ClientIP, ClientPort);
char *Filesize = new char[10];
int Size = 0;
int recv_size, recv_file;
char Buffer[MAXCHAR];
FILE *File;
recv_file = recv(AcceptSocket, Buffer, Size, 0);
recv_size = recv(AcceptSocket, Filesize, 10, 0);
while (Filesize) {
//Menerima File Size
Size = atoi((const char*)Filesize);
File = fopen("D:\\fileReceived.txt", "wb");
fwrite((const char*)Buffer, 1, Size, File);
fclose(File);
printf("File received \n");
ZeroMemory(Buffer, Size);
// printf("File size : %d\n",Size);
recv_file = recv(AcceptSocket, Buffer, Size, 0);
recv_size = recv(AcceptSocket, Filesize, 10, 0);
}
}
}
Client Code
// client.cpp : Defines the entry point for the console application.
#include "stdafx.h"
#include <winsock2.h>
#include <Windows.h>
#include <stdio.h>
using namespace std;
int Size = 0;
char *Buffer;
int _tmain(int argc, _TCHAR* argv[])
{
WORD wVersionRequested;
WSADATA wsaData;
int wsaerr;
wVersionRequested = MAKEWORD(2, 2);
wsaerr = WSAStartup(wVersionRequested, &wsaData);
if (wsaerr != 0) {
printf("The Winsock DLL not found \n ");
} else {
printf("The Winsock DLL found \n ");
}
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
printf("not support Winsock version 2.2 ");
} else {
printf("support winsock version 2.2 \n ");
}
SOCKET Client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (Client_socket == INVALID_SOCKET) {
printf("Error di socket(): %ld\n", WSAGetLastError());
WSACleanup();
} else{
printf("Socket() ok ! \n");
}
SOCKADDR_IN clientService;
clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr("127.0.0.1");
clientService.sin_port = htons(55555);
if (connect(Client_socket, (SOCKADDR*)&clientService, sizeof(clientService)) == SOCKET_ERROR) {
printf("connect() fail ! \n");
} else {
printf(" connect() ok .... \n ");
while (1){
FILE *File;
File = fopen("D:\\logging21.txt", "rb");
if (!File){
printf("", WSAGetLastError());
}
printf("File open ok ! \n");
fseek(File, 0, SEEK_END);
Size = ftell(File);
fseek(File, 0, SEEK_SET);
char cisi[10];
sprintf(cisi, "%i", Size);
// fclose(File);
send(Client_socket, cisi, 10, 0); //file size sent
// Sleep(6000);
Buffer = (char*)malloc(Size + 1);
fread(Buffer, Size, 1, File);
fclose(File);
send(Client_socket, Buffer, Size, 0); // File Binary sent
free(Buffer);
printf("sending finished....\n");
Sleep(6000);
}
}
}
The server is riddled with errors, but this is the most relevant to the asked question: Why can I only send a few bytes?
char *Filesize = new char[10];
int Size = 0; // note the size is set to zero
int recv_size, recv_file;
char Buffer[MAXCHAR];
// no idea how big MAXCHAR is, but it turns out to be irrelevant
FILE *File;
recv_file = recv(AcceptSocket, Buffer, Size, 0);
// Above we use that size of zero to read zero bytes from the socket
recv_size = recv(AcceptSocket, Filesize, 10, 0);
// get the size of the file. This doesn't seem too bad
while (Filesize) { // but we just used a 10 byte blob of data containing who knows what
// as the exit condition from a while loop.
// never use anything from an external source, especially the internet
// without validating and verifying first.
//Menerima File Size
Size = atoi((const char*)Filesize); // atoi fails to convert silently. Use strtol instead.
File = fopen("D:\\fileReceived.txt", "wb"); // open file
fwrite((const char*)Buffer, 1, Size, File);
// write over file contents with what we hope is filesize from a buffer into
// which we read zero bytes. File now full of random crap.
fclose(File);
printf("File received \n");
ZeroMemory(Buffer, Size);
// printf("File size : %d\n",Size);
recv_file = recv(AcceptSocket, Buffer, Size, 0);
// read size of the **last file** (we hope) into buffer
recv_size = recv(AcceptSocket, Filesize, 10, 0);
}
At the very least, filesize must be read before trying to read the file.
Important fun fact about TCP: TCP is a stream, not a packet. Do not assume that because you wrote a number with send that the number is the only thing waiting to be read. For efficiency, TCP packs data together, so if you send "1234" and then a file 1234 bytes long, odds are pretty good both the file size and the file will arrive at the same time. So recv of 10 bytes will very likely read 1234, "1234"'s terminating null, and the first five bytes of the file. It's now up to you to separate the file length from the file data.
But if you send the length as a 32 bit integer, it will always be 4 bytes. Easy, yes? No. Because some computers and network protocols represent numbers backwards. I'm serious here. Google up endian.
Next: recv returns the number of bytes read. You may not get the number of bytes you asked for and have to keep asking until you get the while thing. recv also returns -1 if something goes wrong, so every time you recv, check that the return code is positive and that it's the number of bytes you need before doing anything with the data. Reading a 32 bit filesize, getting only 24 bits, and then trying to use those 24 bits to do meaningful work will really ruin your day.
And there's more! What if MAXCHARS is smaller than the size of the file? Well, that one is easy. You recv MAXCHARS or the number of bytes left in the file and write it out until the file is done.
So:
recv file size
Make sure it's really the filesize and nothing else.
open the output file
while file size is greater than zero
recv up to MAXCHARS or file size, whichever is lower, into buffer
if the number of bytes read is greater than zero
write the number of bytes read from buffer into output file
subtract the number of bytes read from file size
else
something bad happened to the connection. Give up.
close file
You tagged your question as C++ but the code is pretty much entirely C.
Here is a somewhat more C++ version of the server code. To finish the project, your client will need to start by sending a populated "FileTransfer" object, e.g.
FileTransfer xfer(file.size);
auto result = send(send_socket, &xfer, sizeof(xfer), 0);
then send the data from the file, ideally read <= FileTransfer::BufferSize bytes and then push them onto the socket until you have reach all the bytes you promised to send.
// move the code between 8x----x8x into protocol.h
// 8x---- snip ----x8
#pragma once
// protocol.h
#ifndef PROTOCOL_H
#define PROTOCOL_H 1
#include <cstdint>
struct FileTransfer
{
enum { ProtoVersion = 1 };
static const size_t BufferSize = 4 * 4096;
uint32_t m_proto;
size_t m_size;
FileTransfer(size_t size_) : m_proto(ProtoVersion), m_size(size_) {}
FileTransfer() : m_proto(0), m_size(0) {}
};
#endif // PROTOCOL_H
// 8x---- snip ----x8
// server.cpp : Defines the entry point for the console application.
#include "stdafx.h"
#define NOMINMAX
#include <WinSock2.h>
#include <Windows.h>
#include <Ws2tcpip.h>
#include <algorithm>
#include <fstream>
#include <iostream>
//#include "protocol.h"
#pragma comment(lib, "Ws2_32.lib")
void _describeConnection(sockaddr_in& service)
{
char clientIP[128];
inet_ntop(AF_INET, &(service.sin_addr), clientIP, sizeof(clientIP));
auto clientPort = ntohs(service.sin_port);
std::cout << "new connection from " << clientIP << ':' << clientPort << "\n";
}
bool _errorIndicatesInterrupted()
{
auto err = WSAGetLastError();
return (err == WSAEINTR || err == WSAEINPROGRESS);
}
void _receiveFile(SOCKET socket)
{
FileTransfer xfer;
auto recv_size = recv(socket, reinterpret_cast<char*>(&xfer), sizeof(xfer), 0);
if (recv_size < sizeof(xfer)) {
std::cout << "error: only " << recv_size
<< " bytes while recv()ing FileTransfer\n";
return;
}
if (xfer.m_proto != FileTransfer::ProtoVersion) {
std::cout << "error: connection protocol " << xfer.m_proto
<< " not supported\n";
return;
}
if (xfer.m_size <= 0) {
std::cout << "error: zero length transfer\n";
return;
}
std::ofstream out("D:\\fileReceived.txt", std::ios::binary | std::ios::trunc);
char recvBuffer[FileTransfer::BufferSize];
size_t bytesLeft = xfer.m_size;
while (bytesLeft) {
do {
recv_size = recv(socket, recvBuffer, std::min(bytesLeft, FileTransfer::BufferSize), 0);
} while (recv_size < 0 && _errorIndicatesInterrupted());
if (recv_size < 0) {
std::cout << "error: transfer aborted\n";
return;
}
out.write(recvBuffer, recv_size);
bytesLeft -= recv_size;
}
std::cout << "transfered " << xfer.m_size << " bytes\n";
}
bool _server()
{
SOCKET m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_socket == INVALID_SOCKET) {
std::cout << "socket() failed! " << WSAGetLastError() << "\n";
return false;
}
sockaddr_in service;
service.sin_family = AF_INET;
inet_pton(service.sin_family, "127.0.0.1", &service.sin_addr.s_addr);
service.sin_port = htons(55555);
int m_bind = bind(m_socket, (sockaddr*)&service, sizeof(service));
if (m_bind == SOCKET_ERROR) {
std::cout << "bind() failed! " << WSAGetLastError() << "\n";
return false;
}
if (listen(m_socket, 1) == SOCKET_ERROR) {
std::cout << "listen() failed! " << WSAGetLastError() << "\n";
return false;
}
// This code can only accept one connection at a time.
int addresslen = sizeof(service);
for (;;) {
std::cout << "waiting for client...\n";
SOCKET acceptSocket = accept(m_socket, (sockaddr*)&service, &addresslen);
if (acceptSocket < 0) {
std::cout << "accept() failed: " << WSAGetLastError() << "\n";
return false;
}
_describeConnection(service);
_receiveFile(acceptSocket);
closesocket(acceptSocket);
}
}
int _tmain()
{
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 2);
int wsaerr = WSAStartup(wVersionRequested, &wsaData);
if (wsaerr != 0) {
std::cout << "WinSock DLL not found\n";
return 1;
}
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
std::cout << "WinSock 2.2 required\n";
return 1;
}
_server();
// system("PAUSE"); Just use CTRL+F5.
return 0;
}
If this is not a homework project and you are earnestly trying to get a file transfer project set up, consider using one of the libraries mentioned here: Best C/C++ Network Library.

C++ - File is not Full arrived

i want to send a file from client to server through socket . yes it sends a file but the received file in the server is not full or complete like the original one.
So the test file originally has "this is a test" in it, and the received file has "this"
yes it's only 4 letters
i tried to change the original one becomes "MyMomGoesToTheMarket"
and received file has "MyMo" . still 4 letters which is not what i expect.
anyone know how to solve this problem and the solution ?
Here is the client :
#include "stdafx.h"
#include <WinSock2.h>
#include <Windows.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
using namespace std;
SOCKET clientsock;
WSADATA winsock;
sockaddr_in serverAddr , addr;
int Addrlen = sizeof(serverAddr);
FILE *File;
unsigned long Size;
void startClient() {
WSAStartup(MAKEWORD(2,2), &winsock);
if(LOBYTE(winsock.wVersion) != 2 || HIBYTE(winsock.wVersion) != 2 ){
WSACleanup();
}
clientsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(6091);
connect(clientsock,(sockaddr*)&addr,sizeof(addr));
printf("socket connected... \n");
}
void sending() {
//preparing the file
ifstream myfile;
myfile.open("B:\RelativeLayout.txt",ios::in | ios::binary | ios::ate);
if(myfile.is_open()) {
printf("File open OK ! \n ");
}else {
printf("File not open ! \n ", WSAGetLastError());
}
//preparing the file size
long Size ;
myfile.seekg(0,fstream::end);
Size = myfile.tellg();
myfile.close();
printf("File Size : %d bytes.\n ",Size);
char cisi[10];
sprintf(cisi, "%i",Size);
send(clientsock,cisi,10,0); // file size sent
//sending the file
char *rbuffer;
myfile.open("B:\RelativeLayout.txt",ios::in | ios::binary | ios::ate);
if(myfile.is_open()) {
myfile.seekg(0, ios::beg);
rbuffer = new char[Size];
myfile.read(rbuffer, Size);
//send(clientsock, rbuffer, Size, 0);
int j = send(clientsock, rbuffer, Size, NULL); //send to server
if (j == -1){
cout << "Error sending file to server :(" << endl;
}else {
cout << " sending file to server succeed" << endl;
}
myfile.close();
}
}
int _tmain(int argc, _TCHAR* argv[])
{
startClient();
sending();
system("PAUSE");
return 0;
}
and here is the server code :
#include "stdafx.h"
#include <WinSock2.h>
#include <Windows.h>
#include <iostream>
#include <fstream>
using namespace std;
SOCKET servsocket, ClientAcc;
WSAData winsock;
sockaddr_in addr,incomingAddress;
int addrlen = sizeof(sockaddr_in);
int addresslen = sizeof(incomingAddress);
char *Filesize = new char[1024];
long Size;
void start() {
//socket initialization
WSAStartup(MAKEWORD(2,2), &winsock);
//socket check
if(LOBYTE(winsock.wVersion) !=2 || HIBYTE(winsock.wVersion) != 2 ) {
WSACleanup();
}
servsocket = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP);
addr.sin_family = AF_INET;
addr.sin_port = htons(6091);
bind(servsocket, (sockaddr*)&addr, sizeof(addr));
listen(servsocket, 5);
ClientAcc = accept(servsocket, (sockaddr*)&incomingAddress, &addresslen);
char *ClientIP = inet_ntoa(incomingAddress.sin_addr);
int ClientPort = ntohs(incomingAddress.sin_port);
printf("Client Connected ... \n");
printf("IP : %s:%d\n", ClientIP, ClientPort);
}
void receiving() {
//receive the file size
recv(ClientAcc,Filesize,1024,0);
Size = atoi((const char*)Filesize);
printf("File size : %d\n",Size);
//receive the file
char *rbuffer;
rbuffer = new char[Size];
int k = recv(ClientAcc, rbuffer, sizeof(rbuffer), NULL);
if (k < 0){
cout << "Error uploading file" << endl;
}else {
fstream file;
file.open("B:\FileReceived.txt", ios::out|ios::binary| ios::ate);
file.write(rbuffer, sizeof(rbuffer));
file.close();
cout << "File received!" << endl;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
start();
receiving();
system("PAUSE");
return 0;
}
In your server code's recv function, you're passing in sizeof(rbuffer) as the amount of bytes to read in from the socket. rbuffer is a pointer however, and thus taking a sizeof it will return the size of a pointer on your architecture , which is typically 4 or 8 bytes, and since your server code is only reading 4 bytes, sizeof(rbuffer) would return 4 on your system.
To solve this, you need to pass in either Size-1 or strlen(rbuffer)-1 into the call to
int k = recv(ClientAcc, rbuffer, sizeof(rbuffer), NULL);
So it would look like this:
int k = recv(ClientAcc, rbuffer, Size-1, NULL);
This would actually read up to Size-1 bytes from the socket. You would then need to add the null terminator to the end of rbuffer.
rbuffer[k] = '\0';
Additionally, you need to make the same change in this line:
file.write(rbuffer, sizeof(rbuffer));
Which has the same problem as before - it only writes (in this case 4) bytes from rbuffer.

C++ Winsock Sending file [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
a Simple Server and Client that I can send the file,
And I need you guys to see if this source are done.
Cuz I think it won't download the full file.
And maybe to this source have a limit ? Cuz I uploaded/downloaded 200K and a little bit more ..
Server:
#include <WinSock2.h>
#include <Windows.h>
#include <stdio.h>
#pragma comment(lib, "Ws2_32.lib")
SOCKET Socket, Sub;
WSADATA Winsock;
sockaddr_in Addr;
int Addrlen = sizeof(sockaddr_in);
char Buffer[256];
char *Str;
sockaddr_in IncomingAddress;
int AddressLen = sizeof(IncomingAddress);
int main()
{
WSAStartup(MAKEWORD(2, 2), &Winsock); // Start Winsock
if(LOBYTE(Winsock.wVersion) != 2 || HIBYTE(Winsock.wVersion) != 2) // Check version
{
WSACleanup();
return 0;
}
Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
ZeroMemory(&Addr, sizeof(Addr));
Addr.sin_family = AF_INET;
Addr.sin_port = htons(6091);
bind(Socket, (sockaddr*)&Addr, sizeof(Addr));
if(listen(Socket, 1) == SOCKET_ERROR)
{
printf("listening error\n");
}
else
{
printf("listening ok\n");
}
if(Sub = accept(Socket, (sockaddr*)&IncomingAddress, &AddressLen))
{
char *ClientIP = inet_ntoa(IncomingAddress.sin_addr);
int ClientPort = ntohs(IncomingAddress.sin_port);
printf("Client conncted!\n");
printf("IP: %s:%d\n", ClientIP, ClientPort);
printf("Sending file .. \n");
FILE *File;
char *Buffer;
unsigned long Size;
File = fopen("C:\\Prog.exe", "rb");
if(!File)
{
printf("Error while readaing the file\n");
goto End;
}
fseek(File, 0, SEEK_END);
Size = ftell(File);
fseek(File, 0, SEEK_SET);
Buffer = new char[Size];
fread(Buffer, Size, 1, File);
char cSize[MAX_PATH];
sprintf(cSize, "%i", Size);
fclose(File);
send(Sub, cSize, MAX_PATH, 0); // File size
send(Sub, Buffer, Size, 0); // File Binary
free(Buffer);
End:
closesocket(Sub);
closesocket(Socket);
WSACleanup();
}
getchar();
return 0;
}
Client:
#include <WinSock2.h>
#include <Windows.h>
#include <stdio.h>
#pragma comment(lib, "Ws2_32.lib")
SOCKET Socket;
WSADATA Winsock;
sockaddr_in Addr;
int Addrlen = sizeof(Addr);
int main()
{
WSAStartup(MAKEWORD(2, 2), &Winsock); // Start Winsock
if(LOBYTE(Winsock.wVersion) != 2 || HIBYTE(Winsock.wVersion) != 2) // Check version
{
WSACleanup();
return 0;
}
Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
ZeroMemory(&Addr, sizeof(Addr)); // clear the struct
Addr.sin_family = AF_INET; // set the address family
Addr.sin_addr.s_addr = inet_addr("127.0.0.1");
Addr.sin_port = htons(6091); // set the port
if(connect(Socket, (sockaddr*)&Addr, sizeof(Addr)) < 0)
{
printf("Connection failed !\n");
getchar();
return 0;
}
printf("Connection successful !\n");
printf("Receiving file .. \n");
int Size;
char *Filesize = new char[1024];
if(recv(Socket, Filesize, 1024, 0)) // File size
{
Size = atoi((const char*)Filesize);
printf("File size: %d\n", Size);
}
char *Buffer = new char[Size];
if(recv(Socket, Buffer, Size, 0)) // File Binary
{
FILE *File;
File = fopen("Prog.exe", "wb");
fwrite((const char*)Buffer, 1, Size, File);
fclose(File);
}
getchar();
closesocket(Socket);
WSACleanup();
return 0;
}
Thanks.
Your code may fail if you try to send/receive large amount of data. From the documentation of the send function:
Return value
If no error occurs, send returns the total number of
bytes sent, which can be less than the number requested to be sent in
the len parameter. Otherwise, a value of SOCKET_ERROR is returned, and
a specific error code can be retrieved by calling WSAGetLastError.
You have to check the return value of send(), and if it is less than the number of bytes requested to be sent, call send() again for the remaining data. Example:
char *data = Buffer; // data to be sent
int len = Size; // number of bytes to be sent
while (len > 0) {
int amount = send(Sub, data, len, 0);
if (amount == SOCKET_ERRROR) {
// handle error ...
} else {
len -= amount;
data += amount;
}
}
The same is true for the recv() call in the client.
This is the file send function which will read the file as binary and will send the data. This is an independent function just pass the value of the socket on which v need to send the data along with the file path which we need to send.
void FileSend(SOCKET FileSendSocket,char *FilePath)
{
streampos filesize = 0;
ifstream in(FilePath,ios::binary);
ZeroMemory( &sendbuf, sendbuflen);
if(in.is_open())
{
while(1)
{
in.read(sendbuf,sendbuflen);
if(in.eof())
{
cout << "End of File sending from Client" << endl;
in.close();
break;
}
else
{
send(FileSendSocket,sendbuf,sendbuflen,0);
ZeroMemory( &sendbuf, sendbuflen);
}
}
}
}
And this is the receive function on the client side and it should be called just next to the receive function this function will continuously write what ever data the server is sending.
ofstream out("C:\\Prog.exe",ios::binary);
void FileReceive(char* recvbuf, int recvbuflen)
{
if(out.is_open())
{
out.write(recvbuf,recvbuflen);
ZeroMemory(&recvbuf,recvbuflen);
}
}

Problem on Transferring file through TCP with the use of file pointers

i need to transfer a file of 8.3MB over TCP, when i use file pointers to read and write to files then i send about 8.6MB data and also receives 8.6 MB of data by calculating the output of send and recv calls although my file size is 8.3 MB, further the when i check the size of file separately by seeing its properties then it is around 3-5 MB (varies on every transfer) but when i use file descriptors in place of file pointers then i send and recv exactly 8.3 MB of data and file property size also shows 8.3 MB. So what is the problem in using file pointers and why is it removed in case of file descriptors.... but if i use file descriptors then i am not able to read the text file that i sent. Text editors shows some binary data in the file. i am not getting a bit of what is happening... please help and thanks in advance
server.cpp
#include "server.h"
void server()
{
int fd = open("out.txt",O_WRONLY);
struct sockaddr_in sin;
socklen_t addr_size;
char buf[MAX_LINE];
int len;
int s, new_s;
/* build address data structure */
bzero((char *) & sin, sizeof (sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(SERVER_PORT);
printf("File Descriptor : %d", fd);
/* setup passive open */
if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
perror("simplex-talk: socket");
exit(1);
}
if ((bind(s, (struct sockaddr *) & sin, sizeof (sin))) < 0)
{
perror("simplex-talk: bind");
exit(1);
}
listen(s, MAX_PENDING);
// wait for connection, then receive and print text */
while (1)
{
if ((new_s = accept(s, (struct sockaddr *) & sin, &addr_size)) < 0)
{
perror("simplex-talk: accept");
exit(1);
}
float total = 0;
printf("File Descriptor : %d", fd);
while (len = recv(new_s, buf, MAX_LINE, 0) && strcmp(buf,"close"))
{
buf[len] = 0;
total = total+len;
//write(stdout, buf, len);
write(fd, buf, len);
//printf("%fKB and %fMB\n",total/1024, total/(1024*1024));
}
printf("File Descriptor : %d", fd);
close(new_s);
}
}
client.cpp
#include "client.h"
void client(int argc, char** argv)
{
int fd = open("/home/nikku/Desktop/data.txt",O_RDONLY);
if (fd < 0 ) perror("File not opened\n");
struct hostent *hp;
struct sockaddr_in sin;
char *host;
char buf[MAX_LINE];
int s;
int len;
host = argv[1];
if (argc == 2)
{
host = argv[1];
}
else
{
fprintf(stderr, "usage: simplex-talk host\n");
exit(1);
}
/* translate host name into peer’s IP address */
gethostname(host,20);
printf("%s\n",host);
hp = gethostbyname(host);
if (!hp)
{
fprintf(stderr, "simplex-talk: unknown host: %s\n", host);
exit(1);
}
/* build address data structure */
bzero((char *) & sin, sizeof (sin));
sin.sin_family = AF_INET;
bcopy(hp->h_addr, (char *) & sin.sin_addr, hp->h_length);
sin.sin_port = htons(SERVER_PORT);
/* active open */
if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
perror("simplex-talk: socket");
exit(1);
}
if (connect(s, (struct sockaddr *) & sin, sizeof (sin)) < 0)
{
perror("simplex-talk: connect");
close(s);
exit(1);
}
printf("Connection Succeeded\n");
/* main loop: get and send lines of text */
float total = 0;
while (read(fd, buf, MAX_LINE))
{
//usleep(1000);;
len = strlen(buf) + 1;
total += send(s, buf, len, 0);
//printf("%fKB and %fMB\n",total/1024, total/(1024*1024));
}
send(s, "close", 6, 0);
close(fd);
}
Just if i replace use of file descriptors with pointers and use fgets and fputs to read and write then my file transfer does not take properly. But if i use file descriptors then i am not able to read the text file that i sent. Text editors shows some binary data in the file.
while (read(fd, buf, MAX_LINE))
{
//usleep(1000);;
len = strlen(buf) + 1;
total += send(s, buf, len, 0);
//printf("%fKB and %fMB\n",total/1024, total/(1024*1024));
}
There is an issue here, you have no guarantee that read will read a zero byte so strlen(buf) is potentially dangerous. Also note, that as you set len to strlen(buf) + 1, if you do encouter a zero byte you will send it across the socket but if you don't read a zero byte, strlen will read beyond the end of the array and send 'junk' across the socket.
It would be sensible to store the return value of read so that you know how many bytes were actually read from fd.
while (len = recv(new_s, buf, MAX_LINE, 0) && strcmp(buf,"close"))
{
buf[len] = 0;
total = total+len;
//write(stdout, buf, len);
write(fd, buf, len);
//printf("%fKB and %fMB\n",total/1024, total/(1024*1024));
}
Your receive side seems to assume that each call to recv won't include a zero byte as you manually terminate the buffer with a 0. Note that you don't actually have room to do this if recv actually receives MAX_LINE bytes as buf only consists of MAX_LINE elements. As your write is restricted by length in any case, there is no need to do buf[len] = 0;.