Click to See Complete Forum and Search --> : Sending file via send and recv through WinSocks


vamo
July 3rd, 2008, 04:35 AM
Hi!
I have a problem and I cant solve it. I'm new to c++. I have a server application and a client and I want to send a file from the Client to the Server (after a request from the server). I already have some stuff but it doesn't work correctly (copies to much und at the end the file is not the file anymore...). Could anyone fix it for me ...and explain it to me?
(I'm working on windows.)


Server (GUI ... requests the transfer and receives the file.):


else if (LOWORD(wParam) == 7 &&
HIWORD(wParam) == BN_CLICKED &&
(HWND) lParam == downloadButton)
{ // when the download button is clicked it initiates the download...


char location[501];
char buffer[102400];
char temp[101] = {"\0"};

int selected = ListView_GetNextItem(fileBrowse,-1,LVNI_SELECTED);
ListView_GetItemText(
fileBrowse,
selected,
0,
temp,
100
); //file name and location is taken from another field (i hope you don't need it as well...

int length = GetWindowTextLength (listFilesLocation) + 1;
GetWindowText (listFilesLocation, location, length);
strcat(location,temp);

strcpy(buf,"downloadfile");
send(client, buf, sizeof(buf), 0);
strcpy(buf,location);
send(client, buf, sizeof(buf), 0);



char num[10];
int fileSize = recv(client, num, sizeof(num), 0);
// int fileSize = atoi(num);
int count = 0;

std::ofstream myfile;

char myFile[100];
strcpy(myFile,"C:\\theDownloads\\");
strcat(myFile,temp);
myfile.open (myFile, std::ios::out | std::ios::binary);
if (myfile.is_open())
{
myfile.seekp (0, std::ios::beg);

while(count<fileSize)
{
count++;
recv(client, buffer, sizeof(buffer), 0);
myfile.write (buffer, sizeof(buffer));
Sleep(1);
}
myfile.close();
}
SendMessage(terminalWindow, LB_ADDSTRING, 0, (LPARAM) num);
SendMessage(terminalWindow, LB_ADDSTRING, 0, (LPARAM) "File download complete\0");
strcpy(buf,"EOR");
}




Client (commandline porgram) ( waits for a request and sends the file to the server):


else if(!strcmp(buf,"downloadfile"))
{ //starts sending the file after it got the request "downloadfile"
char filePath[256];
char buffer[102400];
recv(kSock, filePath, sizeof(filePath), 0);
std::ifstream myfile;
myfile.open (filePath, std::ios::in | std::ios::binary);
if (myfile.is_open())
{
std::ifstream::pos_type size;
char * memblock;
myfile.seekg (0, std::ios::beg);
int begin = myfile.tellg();
myfile.seekg (0, std::ios::end);
int end = myfile.tellg();
size = (end - begin);
myfile.seekg (0, std::ios::beg);
int i=0;
char num[10];
itoa(size,num,10);
send(kSock, num, sizeof(num), 0);
strcpy(buf,"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
while(i<size)
{
i = i*102400;
myfile.read (buffer, sizeof(buffer));
send(kSock, buffer, sizeof(buffer), 0);
std::cout<<"Packet "<<i<<" sent: "<<sizeof(buffer)<<"\n";
}
delete[] memblock;
myfile.close();
}

strcpy(buf,"EOR\0");
send(kSock, buf, sizeof(buf), 0);
}




Best regards!

MikeAThon
July 3rd, 2008, 10:52 AM
Read this article (for its explanation, not for its code): "Network Transfer Of Files Using MFC's CSocket Class" at http://www.codeproject.com/KB/IP/SocketFileTransfer.aspx

As you will understand from the article, one of your problems is that your code does not check the returned values from the send() and recv() functions, to confirm how many bytes were actually sent and received.

Another problem is the "while" loop in the sending code. What do you hope to accomplish with this:
int i=0;
// ...
while(i<size)
{
i = i*102400;
// ...
}

Mike

vamo
July 3rd, 2008, 01:16 PM
thank you for answer! I will read through your link...


( i don't have i = i*102400; in my code - this is a mistake. there should be i++;)

best regards

MikeAThon
July 3rd, 2008, 02:01 PM
i don't have i = i*102400; in my code - this is a mistake. there should be i++
When you are experiencing difficulties in your code, it is always better to post your actual code, not pseudo-code or fake-code.

Let us know if you still have problems.

Mike

vamo
July 3rd, 2008, 03:13 PM
it was a mistake. by accident i copied an old version but the diverence was only this one mistake... so I didn't see that's the old version. but this time it will be the current one.

okay I have changed my code now. the problem now is that the Client waits for an answer but doesn't receive one (stuck at the recive point before the output "std::cout << "1.2"". o.O somehow the server is stopping there... it doesen't get data from client.

One other very strange thig is that: when i press the download button the second time the client is completing his stuff but the server still didn't get data (length of file and contents)

Server:

else if (LOWORD(wParam) == 7 &&
HIWORD(wParam) == BN_CLICKED &&
(HWND) lParam == downloadButton)
{

char location[512];
//char buffer[512];
char temp[101] = {"\0"};


int selected = ListView_GetNextItem(fileBrowse,-1,LVNI_SELECTED);
ListView_GetItemText(
fileBrowse,
selected,
0,
temp,
100
);

int length = GetWindowTextLength (listFilesLocation) + 1;
GetWindowText (listFilesLocation, location, length);
strcat(location,temp);

strcpy(buf,"downloadfile");
send(client, buf, sizeof(buf), 0);
strcpy(buf,location);
send(client, buf, sizeof(buf), 0);


char rec[50] = "";
char filename[50];
char garbage[50];

strcpy(filename,"C:\\theDownloads\\");
strcat(filename,temp);

recv( client, garbage, 50, 0 );
send( client, "OK", strlen("OK"), 0 );
recv( client, rec, 32, 0 );

SendMessage(terminalWindow, LB_ADDSTRING, 0, (LPARAM) filename);

FILE *fw = fopen(filename, "wb");

int recs = recv( client, rec, 32, 0 );
send( client, "OK", strlen("OK"), 0 );
recv( client, rec, 32, 0 );

rec[recs]='\0';
int size = atoi(rec);


while(size > 0)
{
char buffer[1030];

if(size>=1024)
{
recv( client, buffer, 1024, 0 );
send( client, "OK", strlen("OK"), 0 );
recv( client, rec, 32, 0 );
fwrite(buffer, 1024, 1, fw);

}
else
{
recv( client, buffer, size, 0 );
send( client, "OK", strlen("OK"), 0 );
recv( client, rec, 32, 0 );
buffer[size]='\0';
fwrite(buffer, size, 1, fw);
}


size -= 1024;

}

fclose(fw);


SendMessage(terminalWindow, LB_ADDSTRING, 0, (LPARAM) "File download complete\0");
strcpy(buf,"EOR");
}



Client:


else if(!strcmp(buf,"downloadfile"))
{


char filePath[512];
int length;
//char * buffer;

recv(kSock, filePath, sizeof(filePath), 0);
std::cout << ":" << filePath;
//filePath

// Extract only filename from given path.
char filename[50];
int i=strlen(filePath);
for(;i>0;i--)if(filePath[i-1]=='\\')break;
for(int j=0;i<=(int)strlen(filePath);i++)filename[j++]=filePath[i];
////////////////////////////////////////

std::ifstream myFile(filePath, std::ios::in|std::ios::binary|std::ios::ate);
int size = (int)myFile.tellg();
myFile.close();

char filesize[10];itoa(size,filesize,10);


int test = send( kSock, filename, strlen(filename), 0 );
if ( test == SOCKET_ERROR )
{
return 0;
}
char rec[32] = "";
recv( kSock, rec, 32, 0 );
std::cout << "1.2";
send( kSock, "OK", strlen("OK"), 0 );

std::cout << "2";
send( kSock, filesize, strlen(filesize), 0 );
recv( kSock, rec, 32, 0 );
send( kSock, "OK", strlen("OK"), 0 );

std::cout << "3";
FILE *fr = fopen(filePath, "rb");
std::cout << "\n\nsize:" <<size;
while(size > 0)
{
char buffer[1030];

if(size>=1024)
{
fread(buffer, 1024, 1, fr);
send( kSock, buffer, 1024, 0 );
recv( kSock, rec, 32, 0 );
send( kSock, "OK", strlen("OK"), 0 );

}
else
{
fread(buffer, size, 1, fr);
std::cout << "text: " << buffer << "\n\nsize:" <<size;
buffer[size]='\0';
send( kSock, buffer, size, 0 );
recv( kSock, rec, 32, 0 );
send( kSock, "OK", strlen("OK"), 0 );
}


size -= 1024;

}

fclose(fr);


}


EDIT: i found out that when i check "int test = send( kSock, filename, strlen(filename), 0 );" for its return value that there were 0 bytes sent. but why o.O everything should be correct.

I hope you can help me again.
Best Regards,
Vamo

MikeAThon
July 3rd, 2008, 04:01 PM
// from server's code
recv( client, buffer, 1024, 0 );
send( client, "OK", strlen("OK"), 0 );
recv( client, rec, 32, 0 );
fwrite(buffer, 1024, 1, fw);
Again, you are not checking the returned values from recv and send, to confirm the actual number of bytes that were received or sent. In the above code, for example, although the first call to recv indicates that 1024 bytes can be stored in the buffer, what will happen if only 10 bytes are actually received? Since fwrite is called with "1024", the answer is that you will write 10 bytes of good data followed by 1014 bytes of whatever garbage happened to reside at the end of the buffer.

Please re-read the cited article more carefully.

// from the server's code
int recs = recv( client, rec, 32, 0 );
send( client, "OK", strlen("OK"), 0 );
recv( client, rec, 32, 0 );

rec[recs]='\0';
int size = atoi(rec);
Again, are you certain that this is your actual code? It seems unlikely, since the above code is calling recv twice, into the exact same "rec" buffer. It thus discards the result of the first recv, but then uses the number of bytes received in the first call to recv when processing the second call to recv.

Mike

vamo
July 4th, 2008, 01:31 PM
Hi again! :) I'm getting closer to a solution.... it works almost. just one problem left and this is very strange:

in the following part of my code i recieve the filepath (from the server. stored into "buffer"). Then I create the variable "filePath" and store the value of the buffer - the filepath - in it. After this I open the file and get the length. The next step I store the size I got into buffer and send it to my server... BUT NOW the filesize is ALSO stored in my variable "filePath" o.O but i did only change "buffer". What is the problem? What can I do that I don't lose my "filePath"?


char buffer[4096];
int error;

int recieved = recv(kSock, buffer, sizeof(buffer), 0); //filepath
if ( recieved == SOCKET_ERROR || recieved == 0 )
{
std::cout << WSAGetLastError();
return 0;
}

char * filePath = buffer;

std::ifstream myFile(filePath, std::ios::in|std::ios::binary|std::ios::ate);
int size = (int)myFile.tellg();
myFile.close();

// Filepath still alive here

itoa(size,buffer,10);
int sent = send(kSock, buffer, sizeof(buffer), 0); //sent filesize
if ( sent == SOCKET_ERROR || sent == 0 )
{
std::cout << WSAGetLastError();
return 0;
}

//Filepath gone >.>

std::cout << "korrektes file??: " << filePath << " buffer = (" << buffer << ")\n";
FILE *fr = fopen(filePath, "rb");


Best regards,
Vamo

MikeAThon
July 4th, 2008, 02:28 PM
The next step I store the size I got into buffer and send it to my server... BUT NOW the filesize is ALSO stored in my variable "filePath" o.O but i did only change "buffer". What is the problem?
char * filePath = buffer;
You didn't allocate any memory for the "filePath" variable. It points to the same memory as that occupied by "buffer".

Incidentally,
int sent = send(kSock, buffer, sizeof(buffer), 0); //sent filesize
should probably be
int sent = send(kSock, buffer, strlen(buffer), 0); //sent filesize
or else you will send a bunch of garbage bytes after the NULL terminator.

Mike

vamo
July 5th, 2008, 01:32 PM
okay thank you. it's working pretty fine now. ...

thank you for all of your help! (I will come again ;-) )
Vamo