C++ WinSock sending files - c++

Recently, i've been assigned a client/server project, which is basically a chat room, where files can be sent and recieved, and we can use webcams.
I'm currently working on the file transfer part, and after looking at some online tutorials, i've noticed most of them use offsets to write into their buffers, then they write the whole buffer into their new file.
To replicate that kind of code, i've set up 2 buffers, one on the client side, the other on the server side. On the server side, i read 8192 bytes from my file, into the buffer, then i send it into the client side, which recieves it, and adds it to my buffer. Problem is, after the second file transfer, every single transfer it does, it's a SOCKET_ERROR, which probably means something's not quite right.
server:
std::ifstream readFile;
readFile.open(FileName, std::ios::binary | std::ios::ate);
if (!readFile)
{
std::cout << "unable to open file" << std::endl;
}
int FileSize = readFile.tellg();
readFile.seekg(0);
int remainingBytes = 0;
uint32_t FileSize32t = (uint32_t)FileSize;
FileSize32t = htonl(FileSize32t);
send(connections[ID], (char*)&FileSize32t, sizeof(uint32_t), 0);
int sent_bytes = 0;
int offset = 0;
char data[8192];
remainingBytes = FileSize;
int i = 0;
while (i<6)
{
readFile.read(data, 8192);
if (remainingBytes < 8192)
{
sent_bytes = send(connections[ID], data+offset, remainingBytes, 0);
remainingBytes -= sent_bytes;
offset += sent_bytes;
}
else
{
sent_bytes = send(connections[ID], data+offset, 8192, 0);
if (sent_bytes == SOCKET_ERROR)
{
std::cout << "erro" << std::endl;
}
remainingBytes -= sent_bytes;
offset += sent_bytes;
std::cout <<"offset: "<< offset << std::endl;
std::cout << "Sent bytes: " << sent_bytes << std::endl;
std::cout << "remaining bytes: " << remainingBytes << std::endl;
}
i++;
}
Client:
char data[8192];
std::ofstream writeFile;
writeFile.open("Putin.jpg", std::ios::binary);
int bytesReceieved = 0;
int totalBytesReceieved = 0;
int i = 0;
while (i<6)
{
if (recvFileSize - totalBytesReceieved < 8192)
{
bytesReceieved = recv(connection, data+totalBytesReceieved, recvFileSize - totalBytesReceieved, 0);
totalBytesReceieved += bytesReceieved;
}
else
{
bytesReceieved = recv(connection, data + totalBytesReceieved, 8192, 0);
totalBytesReceieved += bytesReceieved;
std::cout << totalBytesReceieved << std::endl;
}
i++;
}
writeFile.write(data, totalBytesReceieved);
std::cout << "transferĂȘncia terminada, bytes recebidos: " << totalBytesReceieved << std::endl;
writeFile.close();
Do note that this is just a test program, and it's preety much one of my first interactions with C++. I've been told this probably isn't the best way to start off with C++, but i need this assignment done until the 15th of september, so i need to finish it regardless. If you find any errors or problems besides my original issue do feel free to point them out and if you can, explain me why it's wrong.
Thank you very much for your help.

Related

Sending files over TCP using C++, recving wrong size

I am very new to socket programming, and i am trying to send over TCP connection but getting few errors.
here is my code
FILE* File;
char* Buffer;
unsigned long Size;
File = fopen("C:\\test.zip", "rb");
if (!File)
{
printf("Error while readaing the file\n");
return;
}
// file size 1
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);
cout << "MAX PATH " << MAX_PATH<<endl;
cout << "cSize: " << cSize << endl;
fclose(File);
`
So this to find the size of my file. most of the code i am trying it out from other questions in here but it didnt solve my problem.
'
my send and recv:
unsigned long filechunk = 1025;
unsigned long byteSent = 0;
unsigned long bytesToSend = 0;
send(Sub, cSize, MAX_PATH, 0); // File size to client
while (byteSent < Size) {
if ((Size - byteSent) >= filechunk) {
bytesToSend = filechunk;
}
else {
bytesToSend = Size - byteSent;
}
if (send(Sub, Buffer + byteSent, bytesToSend, 0)) {
std::cout << "Sent: ";
}
byteSent += bytesToSend;
std::cout << "Size : "<<Size<<" BytesSent : "<<byteSent<<" Bytes to send: " << bytesToSend << std::endl;
system("pause");
on the client side:
int Size;
char* Filesize = new char[5000000]; // is there a better way? my sfiles size are unknown but at least 50mb
if (recv(Socket, Filesize, 5000000, 0)) // File size
{
Size = atoi((const char*)Filesize);
printf("File size: %d\n", Size);
}
char* Buffer = new char[Size];
FILE* File;
File = fopen("test.zip", "wb"); //start copying from the server, creating the file first.
std::string convert;
long conv;
std::cout << "Size: " << Size << std::endl;
int total=Size;
int byteRecv = 0;
int recvCheck;
int bytes = 1025;
//getting the file
while (byteRecv < Size ) {
recvCheck = recv(Socket, Buffer, bytes, 0);
if (recvCheck >0) // File
{
fwrite(Buffer, 1, byteRecv, File);
std::cout << "Recieved:" << byteRecv << std::endl;
Size -= byteRecv;
byteRecv += byteRecv;
std::cout << "Error: " << WSAGetLastError();
}
else {
std::cout << "Error: " << WSAGetLastError();
total += 1; // the loop often get into infinit loop so i force it in case of this error.
if (total > 3) {
break;
}
}
}
fclose(File);
So, i know it is not very efficient and i am not sure if there are similar questions as i have been digging in here for a few weeks now.
-is there a better way i can make a char*[]? as i dont know the size of the files i want to send yet.
- does ftell() and sifeof() work the same way?
-when i check for the size i recved from the server it is alays wrong. Ex: server file: 32633513, recv size: 3263
-most of the code i have taken from other problems and combined it. if you see anything that is not needed do tell me so i take notes of that.
There is a lot of wrong things but that may correct your problem at first:
On the client side replace (your are both decrementing the total count of bytes and the received ones with the wrong value):
Size -= byteRecv;
byteRecv += byteRecv;
with:
byteRecv += recvCheck; // actualizes the count of received bytes
The other problem is your buffer size. Never try to get an entire file in memory, this is nonsense in general; files are usually managed chunks by chunks. As you are reading at most 1025 bytes in each loop, then only use a buffer of size 1025, you don't need more. Same for reading and writing...

OpenAL reading a WAV file lib

I am just getting started with OpenAL for a Game Engine that I am building. My understanding is that there are some libraries that can help you open an use .wav files. I understand that ALUT is deprecated, but I have heard mention of a more current library called libaudio. I cannot, however, find that library online anywhere.
My question is this: Where can I find libaudio? Or is there a better, more maintained library out there like alut that I can use? I really don't want to have to learn how to open a .wav file if I can help it. Any suggestions would be great.
I broke down and wrote it manually based on this awesome tutorial: https://www.youtube.com/watch?v=tmVRpNFP9ys
Here is the code:
//check big vs little endian machine
static bool IsBigEndian(void)
{
int a = 1;
return !((char*)&a)[0];
}
static int ConvertToInt(char* buffer, int len)
{
int a = 0;
if(!IsBigEndian())
{
for(int i = 0; i < len; ++i)
{
((char*)&a)[i] = buffer[i];
}
}
else
{
for(int i = 0; i < len; ++i)
{
((char*)&a)[3-i] = buffer[i];
}
}
return a;
}
//Location and size of data is found here: http://www.topherlee.com/software/pcm-tut-wavformat.html
static char* LoadWAV(string filename, int& channels, int& sampleRate, int& bps, int& size)
{
char buffer[4];
std::ifstream in(filename.c_str());
in.read(buffer, 4);
if(strncmp(buffer, "RIFF", 4) != 0)
{
std::cout << "Error here, not a valid WAV file, RIFF not found in header\n This was found instead: "
<< buffer[0] << buffer[1] << buffer[2] << buffer[3] << std::endl;
}
in.read(buffer, 4);//size of file. Not used. Read it to skip over it.
in.read(buffer, 4);//Format, should be WAVE
if(strncmp(buffer, "WAVE", 4) != 0)
{
std::cout << "Error here, not a valid WAV file, WAVE not found in header.\n This was found instead: "
<< buffer[0] << buffer[1] << buffer[2] << buffer[3] << std::endl;
}
in.read(buffer, 4);//Format Space Marker. should equal fmt (space)
if(strncmp(buffer, "fmt ", 4) != 0)
{
std::cout << "Error here, not a valid WAV file, Format Marker not found in header.\n This was found instead: "
<< buffer[0] << buffer[1] << buffer[2] << buffer[3] << std::endl;
}
in.read(buffer, 4);//Length of format data. Should be 16 for PCM, meaning uncompressed.
if(ConvertToInt(buffer, 4) != 16)
{
std::cout << "Error here, not a valid WAV file, format length wrong in header.\n This was found instead: "
<< ConvertToInt(buffer, 4) << std::endl;
}
in.read(buffer, 2);//Type of format, 1 = PCM
if(ConvertToInt(buffer, 2) != 1)
{
std::cout << "Error here, not a valid WAV file, file not in PCM format.\n This was found instead: "
<< ConvertToInt(buffer, 4) << std::endl;
}
in.read(buffer, 2);//Get number of channels.
//Assume at this point that we are dealing with a WAV file. This value is needed by OpenAL
channels = ConvertToInt(buffer, 2);
in.read(buffer, 4);//Get sampler rate.
sampleRate = ConvertToInt(buffer, 4);
//Skip Byte Rate and Block Align. Maybe use later?
in.read(buffer, 4);//Block Align
in.read(buffer, 2);//ByteRate
in.read(buffer, 2);//Get Bits Per Sample
bps = ConvertToInt(buffer, 2);
//Skip character data, which marks the start of the data that we care about.
in.read(buffer, 4);//"data" chunk.
in.read(buffer, 4); //Get size of the data
size = ConvertToInt(buffer, 4);
if(size < 0)
{
std::cout << "Error here, not a valid WAV file, size of file reports 0.\n This was found instead: "
<< size << std::endl;
}
char* data = new char[size];
in.read(data, size);//Read audio data into buffer, return.
in.close();
return data;
}

Access violation reading location when using ReadFile

I`m struggling for the past many hours with the following problem: I try to read a file using CreateFile and ReadFile methods.
Here is the code:
char* Utils::ReadFromFile(wchar_t* path) {
HANDLE hFile = CreateFile(
path, // long pointer word string file path (16 bit UNICODE char pointer)
GENERIC_READ, // access to file
0, // share mode ( 0 - prevents others from opening/readin/etc)
NULL, // security attributes
OPEN_EXISTING, // action to take on file -- returns ERROR_FILE_NOT_FOUND
FILE_ATTRIBUTE_READONLY, // readonly and offset possibility
NULL // when opening an existing file, this parameter is ignored
);
if (hFile == INVALID_HANDLE_VALUE) {
std::cout << "File opening failed" << endl;
std::cout << "Details: \n" << Utils::GetLastErrorMessage() << endl;
CloseHandle(hFile);
hFile = NULL;
return nullptr;
}
LARGE_INTEGER largeInteger;
GetFileSizeEx(hFile, &largeInteger);
LONGLONG fileSize = largeInteger.QuadPart;
if (fileSize == 0) {
std::cout << "Error when reading file size" << endl;
std::cout << "Details: \n" << Utils::GetLastErrorMessage() << endl;
CloseHandle(hFile);
hFile = NULL;
return nullptr;
}
cout << "File size: " << fileSize << endl;
char* bytesRead;
bytesRead = new char(fileSize);
int currentOffset = 0;
int attempts = 0;
int nBytesToBeRead = BYTES_TO_READ;
//DWORD nBytesRead = 0;
OVERLAPPED overlap{};
errno_t status;
while (currentOffset < fileSize) {
overlap.Offset = currentOffset;
if (fileSize - currentOffset < nBytesToBeRead)
nBytesToBeRead = fileSize - currentOffset;
status = ReadFile(
hFile, // file handler
bytesRead + currentOffset, // byted read from file
nBytesToBeRead, // number of bytes to read
NULL, // number of bytes read
&overlap // overlap parameter
);
if (status == 0) {
std::cout << "Error when reading file at offset: " << currentOffset << endl;
std::cout << "Details: \n" << Utils::GetLastErrorMessage() << endl;
attempts++;
std::cout << "Attempt: " << attempts << endl;
if (attempts == 3) {
cout << "The operation could not be performed. Closing..." << endl;
CloseHandle(hFile);
hFile = NULL;
return nullptr;
}
continue;
}
else {
cout << "Read from offset: " << currentOffset;// << " -- " << overlap.InternalHigh << endl;
currentOffset += nBytesToBeRead;
if (currentOffset == fileSize) {
cout << "File reading completed" << endl;
break;
}
}
}
CloseHandle(hFile);
return bytesRead;
}
When running this method I get some weird results:
One time it worked perfectly
Very often I get Access violation reading location for currentOffset variable and overlap.InternalHigh ( I commented last one), with last method from CallStack being
msvcp140d.dll!std::locale::locale(const std::locale & _Right) Line 326 C++
Sometimes the function runs perfectly, but I get access violation reading location when trying to exit main function with last method from CallStack being
ucrtbased.dll!_CrtIsValidHeapPointer(const void * block) Line 1385 C++
I read the windows documentation thoroughly regarding the methods I use and checked the Internet for any solution I could find, but without any result. I don't understand this behaviour, getting different errors when running cod multiple times, and therefore I can`t get to a solution for this problem.
Note: The reason I am reading the file in repeated calls is not relevant. I tried reading with a single call and the result is the same.
Thank you in advance
You are allocating a single char for bytesRead, not an array of fileSize chars:
char* bytesRead;
bytesRead = new char(fileSize); // allocate a char and initialize it with fileSize value
bytesRead = new char[fileSize]; // allocate an array of fileSize chars

Sending Picture via TCP

I'm trying to send a jpg file from a client to a server using TCP. When the picture arrives to the server side I can't open it, besides the size of the picture received is higher than the one sent (sent = 880 bytes , received = 894 bytes). Any one of you have an idea of how to do solve this problem ? Here is my code :
client code :
static int send_server_image(SOCKET sock){
int n = 0;
int siz = 0;
FILE *picture;
char buf[50];
char *s="";
cout << "Getting image size" << endl;
picture = fopen("C:\\Users\\n.b\\Desktop\\c++\\TCP\\tcp_client_image_pp\\test.jpg", "r");
fseek(picture, 0, SEEK_END);
siz = ftell(picture);
cout << siz << endl; // Output 880
cout << "Sending picture size to the server" << endl;
sprintf(buf, "%d", siz);
if((n = send(sock, buf, sizeof(buf), 0)) < 0)
{
perror("send_size()");
exit(errno);
}
char Sbuf[siz];
cout << "Sending the picture as byte array" << endl;
fseek(picture, 0, SEEK_END);
siz = ftell(picture);
fseek(picture, 0, SEEK_SET); //Going to the beginning of the file
while(!feof(picture)){
fread(Sbuf, sizeof(char), sizeof(Sbuf), picture);
if((n = send(sock, Sbuf, sizeof(Sbuf), 0)) < 0)
{
perror("send_size()");
exit(errno);
}
memset(Sbuf, 0, sizeof(Sbuf));
}
}
server code :
static int recv_client_image(SOCKET sock){
int n = 0;
cout << "Reading image size" << endl;
char buf[50];
int siz = 0;
if ((n = recv(sock, buf, sizeof(buf), 0) <0)){
perror("recv_size()");
exit(errno);
}
siz = atoi(buf);
cout << siz << endl; // 880 output
char Rbuffer[siz];
cout << "Reading image byte array" << endl;
n = 0;
if ((n = recv(sock, Rbuffer, sizeof(Rbuffer), 0)) < 0){
perror("recv_size()");
exit(errno);
}
cout << "Converting byte array to image" << endl;
FILE *image;
image = fopen("recu.jpg", "w");
fwrite(Rbuffer, sizeof(char), sizeof(Rbuffer), image);
fclose(image);
cout << "done" << endl;
}
Thank you.
You are using Variable Length Arrays, which is not standard C++ (ref). Even if it is accepted by your compiler, you should avoid using sizeof on that.
And you have a problem in the while(!feof(picture)). You read siz bytes from the file without any error and without setting the eof flag. On second read, you read 0 bytes and set the flag but also send another buffer.
You should write instead:
while(!feof(picture)){
n = fread(Sbuf, sizeof(char), siz, picture);
if (n > 0) { /* only send what has been read */
if((n = send(sock, Sbuf, siz, 0)) < 0) /* or (better?) send(sock, Sbuf, n, 0) */
{
perror("send_data()");
exit(errno);
}
}
/* memset(Sbuf, 0, sizeof(Sbuf)); useless for binary data */
}
Same in server part:
if ((n = recv(sock, Rbuffer, siz, 0)) < 0){
perror("recv_size()");
exit(errno);
}
cout << "Converting byte array to image" << endl;
FILE *image;
image = fopen("recu.jpg", "w");
fwrite(Rbuffer, sizeof(char), siz, image);
fclose(image);
And there is a last possibility of error, at least if you are on a platform that makes a difference between text and binary file like Windows is that you forget to open the files in binary mode, which could break the jpg image. Because on windows for a binary file, byte 0x10 is seen as the new line (\n') and written as 2 bytes 0x0d 0x10 (\r\n).
So you must open the input file in rb mode and the output file in wb mode.
Solved :
All the correction that Serge Ballesta were right. But the problem was in the way I was opening my files.
You need to open the file in binary mode ("rb" for reading, "wb" for writing), not the default text mode.
Client :
picture = fopen("C:\\Users\\n.b\\Desktop\\c++\\TCP\\tcp_client_image_pp\\test.jpg", "rb");
Server :
image = fopen("recu.jpg", "wb");
That was the main problem. Thank you.

C++ <policy-file-request />

hopefully this will be my last C++ question related to sockets.
I have a .SWF file and it sends a policy file request.
I check if my incoming data char 0 is <, so like this:
if (raw[0] == '<')
Then I send my policy shit:
send(this->s, Env::Policy().c_str(), sizeof(Env::Policy()), 0);
std::cout << "Sent " << Env::Policy().c_str() << std::endl;
running = false;
closesocket(this->s);
break;
break; will stop the while (this->running) loop.
My policy string:
std::string Env::Policy()
{
char c = 0;
return "<?xml version=\"1.0\"?>\r\n<!DOCTYPE cross-domain-policy SYSTEM \"/xml/dtds/cross-domain-policy.dtd\">\r\n<cross-domain-policy>\r\n<allow-access-from domain=\"*\" to-ports=\"1-31111\" />\r\n</cross-domain-policy>" + c;
}
But every time I send it, nothing happens. The socket won't receive a new connection (like in C# socket server). But when I reconnect on the .swf, it will accept a new connection.
What's going on?
My full while(this->running) loop:
while (running)
{
char c[256];
int bits = recv(s, c, sizeof(c), 0);
if (bits > 0)
{
std::string data = c;
std::string raw = data.substr(0, bits);
std::cout << "First char: " << raw[0] << std::endl;
if (raw[0] == '<')
{
send(this->s, Env::Policy().c_str(), sizeof(Env::Policy()), 0);
std::cout << "Sent " << Env::Policy().c_str() << std::endl;
running = false;
closesocket(this->s);
break;
}
int header = Env::B64Decode(raw.substr(3, 2));
switch (header)
{
case 202:
this->msg = new ServerMessage("DA");
this->msg->AddInt32(6);
this->msg->AddInt32(0);
this->msg->AddInt32(1);
this->msg->AddInt32(1);
this->msg->AddInt32(1);
this->msg->AddInt32(3);
this->msg->AddInt32(0);
this->msg->AddInt32(2);
this->msg->AddInt32(1);
this->msg->AddInt32(4);
this->msg->AddInt32(1);
this->msg->AddString("dd-MM-yyyy");
this->msg->AddChar(2);
this->sendData(this->msg->toString());
this->msg = new ServerMessage("#H");
this->msg->AddString("[100,105,110,115,120,125,130,135,140,145,150,155,160,165,170,175,176,177,178,180,185,190,195,200,205,206,207,210,215,220,225,230,235,240,245,250,255,260,265,266,267,270,275,280,281,285,290,295,300,305,500,505,510,515,520,525,530,535,540,545,550,555,565,570,575,580,585,590,595,596,600,605,610,615,620,625,626,627,630,635,640,645,650,655,660,665,667,669,670,675,680,685,690,695,696,700,705,710,715,720,725,730,735,740]");
this->msg->AddChar(2);
this->sendData(this->msg->toString());
break;
default:
std::cout << "Unregistered header " << header << std::endl;
break;
}
}
else
{
break;
}
}
std::string data = c;
is only good if the string is surely 0-terminated
std::string raw = data.substr(0, bits);
you could do that simpler
const std::string raw(c, c+bits);
in your policy function there's a char c for no reason, but if it had value >0, would likely cause problems.
And most importantly, sending sizeof(Env::Policy()) bytes makes no sense at all, you shall send the whole string!
const auto& policy = Env::Policy();
send(this->s, policy, policy.size() + 1, 0);
maybe without +1, depending if you want the 0.