Sending Picture via TCP - c++

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.

Related

Unable to send the message again using C socket

I have created a ClientSocket and a ServerSocket class for simplifying functions. while sending a data, at first I am sending a 16 bytes header containing the message length followed by the message. But I am having trouble while sending data from client to server on the 2nd time. At first it is sending the header and the message properly but after that I am getting 0 bytes output from read() in ServerSocket::get_message while reading the header from the client. Please help me out here.
Sending and receiving part in Server.cpp
string ServerSocket::get_message(int client_socket_fd) {
//char *header = client_buffers[client_socket_fd].read_header;
char *read_buffer = client_buffers[client_socket_fd].read_buffer;
char header[16];
memset(header, 0, sizeof(header));
int read_result = -1;
read_result = read(client_socket_fd, header, 16);
cout << read_result << endl;
if (read_result > 0){
int read_size = stoi(string(header));
cout << read_size << endl;
memset(read_buffer, 0, sizeof(read_buffer));
read_result = read(client_socket_fd, read_buffer,read_size);
if (read_result > 0) return string(read_buffer);
}
cerr << "Unable to recieve message from client socket " << client_socket_fd << endl;
return "";
}
int ServerSocket::_send(int client_socket_fd, string message) {
//char *header = client_buffers[client_socket_fd].write_header;
char *write_buffer = client_buffers[client_socket_fd].write_buffer;
char header[16];
memset(header, 0, sizeof(header));
string write_size = to_string(message.length());
copy(write_size.begin(), write_size.end(), header);
int write_result = write(client_socket_fd, header, 16); // sending size of message
if (write_result > 0) {
write_result = write(client_socket_fd, message.c_str(), message.length());
}
if (write_result <= 0)
cerr << "Unable to send to client socket fd : " << client_socket_fd << endl;
return write_result;
}
Sending and receiving part in Client.cpp
string ClientSocket::_recieve(){
char read_header[16];
memset(read_header, 0, sizeof(read_header));
int read_result = read(socket_fd, read_header, 16);
if (read_result >0) {
int read_size = stoi(string(read_header));
memset(recieve_buffer, 0, sizeof(recieve_buffer));
read_result = read(socket_fd, recieve_buffer, read_size);
}
if ( read_result > 0) return string(recieve_buffer);
cerr << "Unable to read from server." << endl;
return "";
}
int ClientSocket::_send(string message) {
char write_header[16];
memset(write_header, 0, sizeof(write_header));
cout << message.length() << endl;
string s = to_string(message.length());
copy(s.begin(),s.end(), write_header);
int write_result = write(socket_fd, write_header, 16);
if (write_result > 0)
write_result = write(socket_fd, message.c_str(), message.length());
if (write_result <=0) cerr << "Unable to send message : "<< message << endl;
return write_result;
}
The code exhibits the two most frequent errors when using sockets:
Socket send/write and recv/read may not send/receive the number of bytes requested. The code must handle partial reads/writes in order to work correctly.
The received socket data is not zero-terminated. You need to zero-terminate the received data before passing it to functions that expect zero-terminated stings (std::string and stoi here). memset doesn't help when recv fills the entire buffer, you need to reserve one extra byte for the null terminator that recv doesn't overwrite.

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;
}

C++ WinSock sending files

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.

ofstream not outputting when I don't have a endl c++

I have a client/server socket program that writes packets of file data in a char[2048], I've made 100% sure to null terminate all of the arrays before sending over the socket.
However on the server side I can't get the ofstream to output to the file if I do not have an endl, however this endl inserts itself at the end of the packets and makes the file have newlines in them where I don't want them to.
Here is what should be the relevant code
client
void Copy(char *filename1,string filename2,int Sockfd) {
const int BUFSIZE=2048;
char buffer[BUFSIZE];
ifstream fin;
long filelen, bytesRemaining, bytes;
// Open the file to be transferred, check it exists.
fin.open( filename1);
if (!fin.good()) {
cerr << "Problems opening \"" << filename1 << "\" (" << errno << "): " << strerror(errno) << endl;
exit(1);
}
// Determine the file's length.
fin.seekg(0,ios::end);
if(fin.fail()) cerr<<"seekg() fail!\n";
filelen = fin.tellg();
if(fin.fail()) cerr<<"tellg() fail!\n";
fin.seekg(0, ios::beg);
if(fin.fail()) cerr<<"seekg() fail!\n";
// Copy the file data.
bytesRemaining = filelen;
while (bytesRemaining > 0)
{
bytes = bytesRemaining > BUFSIZE ? BUFSIZE : bytesRemaining;
buffer[bytes] = '\0';
fin.read(buffer,bytes);
if(fin.fail())
{
cerr<<"read() errror\n";
exit(1);
}
send(Sockfd,buffer,sizeof buffer,0);
recv(Sockfd,buffer,strlen(buffer),0);
bytesRemaining -= bytes;
}
fin.close();
}
And Server
int retval;
char EchoBuffer[RCVBUFSIZE]; // Buffer for echo string
int RecvMsgSize; // Size of received message
std::ofstream fout;
fout.open("test.txt",std::ios::ate);
// Send received string and receive again until end of transmission
while(RecvMsgSize > 0)
{ // zero indicates end of transmission
// Echo message back to client
if(send(ClntSocket, EchoBuffer, RecvMsgSize, 0) != RecvMsgSize){
perror("send() failed"); exit(1);
}
// See if there is more data to receive
if((RecvMsgSize = recv(ClntSocket, EchoBuffer, RCVBUFSIZE-1, 0)) < 0){
perror("recv() failed"); exit(1);
}
EchoBuffer[RecvMsgSize] = '\0';
fout << EchoBuffer << endl; //If I don't have this endl, it won't work at all
}
fout.close();
close(ClntSocket); // Close client socket
}
You should write fout.flush(); after fout << EchoBuffer;.