Re: CAsyncSocket and Send



"Vinoj" <Vinoj@xxxxxxxxxxxxxxxxxxxxxxxxx> wrote in message
news:21D3AC8A-8AB8-4051-BF14-8ED32922E5DF@xxxxxxxxxxxxxxxx
> I'm using TCP/IP. I'm also sending/receivingbinary data (file transfer).
>
> The sending side sends an 'f' char immediately before a file is sent.
When
> the 'f' is received, the receive file routine is called (which receives
the
> file name - 256 chars, the file size, and then the file data). After
that,
> occasionally there will be no more data (expected), however, sometimes
there
> more data on the socket. The receive file routine follows (adapted from
Mike
> O'Niell's CSocket file transfer tutorial). Thanks.
>
> Vinoj

The code you posted does not execute an "asynchronous" file transfer.
Rather, the code is ocmpletely synchronous, since it executes, seriatim,
reception of file name, followed by size, followed by data; and it does not
complete until all tasks are also complete.

An asynchronous file transfer would perform a single call to Receive() in
response to an FD_READ notification (i.e., inside your
CAsyncSocket::OnReceive() override), and then exit after updating your state
machine, to await again a new FD_READ notification. The serial tasks shown
in your function (below) would be "cobbled together" after multiple calls to
OnReceive(), based on logic in your state machine.

The various calls to Sleep() were probably needed to make the code "work",
in the sense that a file was successfully received without a
WSAGetLastError() of WSAEWOULDBLOCK. This alone should be enough to
demonstrate to you that the code is not asynchronous, but rather very
synchronous and sequential.

As for "garbage being sent after data", if you are using
http://www.codeproject.com/internet/SocketFileTransfer.asp , then nothing at
all is being sent after the data, since the sending code specifically sends
less than a full buffer at the end of a file (it only sends the final part
of the file, which usually is less than a full buffer). On the receiving
side, at the end of the file, the code is designed to write to the output
file only the number of bytes remaining in the file, and not the entire
buffer (i.e., the code writes to the file based on iiRecd (which is the
number of bytes received) and not based on RECV_BUFFER_SIZE (which is the
size of the buffer)).

So, the only source of this behavior is if you are sending multiple files,
and you do not correctly handle the point of demarcation between sending of
the current file and that of a prior file.

See specific notes on your code, below.

Mike


>
> BOOL AsyncReceiveFile(CString FilePath){
>
> BOOL bRet = TRUE; // return value
> int dataLength, cbBytesRet, cbLeftToReceive, loop = 0;
> BYTE* recdData = NULL;
>
> CFile destFile;
> char buff[256];
> BOOL bFileIsOpen = FALSE;
> Sleep(200);
> CString strFileName;
>
> //receive the filename
> memset(buff, 0, sizeof(buff));
> cbLeftToReceive = MAX_FILENAME_LENGTH;
> do{
> cbBytesRet = pAsyncClient->Receive(buff, cbLeftToReceive, 0);


This code is wrong, since it always loads the most-recently-received part of
the file name to the beginning of the buffer. It should be something like
this:

cbBytesRet = pAsyncClient->Receive(buff+MAX_FILENAME_LENGTH-cbLeftToReceive,
cbLeftToReceive, 0);



> if(cbBytesRet > 0)
> cbLeftToReceive -= cbBytesRet;
> else if(++loop > 1000)
> return FALSE;
> }
> while(cbLeftToReceive >0);


This test makes sense only if the file name is always exactly
MAX_FILENAME_LENGTH in length, and only if both sides agree on the value of
MAX_FILENAME_LENGTH. As a better alternative, why not prefix the file name
with the byte-count of the nae itself, much like you do when sending the
file's data.



>
> strFileName = buff;
> // open/create target file that receives the transferred data
>
> if(!(bFileIsOpen = destFile.Open((LPCTSTR)strFileName,
> CFile::modeCreate|CFile::modeWrite|CFile::typeBinary))){
> MessageBeep(MB_ICONEXCLAMATION);
>
> // Open Error Log File and Record Problem
> }
> return FALSE;
> }
>
> // get the file's size
> Sleep(200);
> cbLeftToReceive = sizeof(dataLength);
> loop = 0;
>
> do{
> BYTE* bp = (BYTE*)(&dataLength) + sizeof(dataLength) -
> cbLeftToReceive;
> cbBytesRet = pAsyncClient->Receive( bp, cbLeftToReceive );
>
> // test for errors and get out if they occurred
> if(cbBytesRet == SOCKET_ERROR || cbBytesRet == 0){
> int iErr = ::GetLastError();
> if(iErr != WSAEWOULDBLOCK){
>
> MessageBeep(MB_ICONEXCLAMATION);
>
> // Open Error Log File and Record Problem }
>
> return FALSE;
> }
> cbLeftToReceive += cbBytesRet;
>
> //if data cannot be read
> if(++loop > 1000)
> return FALSE;
> }
>
> cbLeftToReceive -= cbBytesRet;
>
>
>
> }
> while (cbLeftToReceive > 0);
>
> if((dataLength = ntohl( dataLength )) < 0){
> MessageBeep(MB_ICONEXCLAMATION);
>
> // Open Error Log File and Record Problem
> }
> return FALSE;
> }
>
>
> // now get the file in RECV_BUFFER_SIZE chunks at a time
> Sleep(200);
> recdData = new byte[BUFFER_SIZE];
> cbLeftToReceive = dataLength;
> loop = 0;
> do{
> int iiGet, iiRecd;
>
> iiGet = (cbLeftToReceive<BUFFER_SIZE)?cbLeftToReceive:BUFFER_SIZE
;
> iiRecd = pAsyncClient->Receive( recdData, iiGet );
>
> // test for errors and get out if they occurred
> if (iiRecd == SOCKET_ERROR || iiRecd == 0){
> int iErr = ::GetLastError();
> if(iErr != WSAEWOULDBLOCK){
> //Record error
>
> delete [] recdData;
> return FALSE;
> }
> cbLeftToReceive += iiRecd;
>
> if(++loop > 1000)
> return FALSE;
> }
>
> // good data was retrieved, so accumulate
> // it with already-received data
> if(iiRecd > 0)
> destFile.Write( recdData, iiRecd); // Write it
> cbLeftToReceive -= iiRecd;
>
>
> }
> while ( cbLeftToReceive > 0 );
>
>
> delete[] recdData;
>
> if ( bFileIsOpen )
> destFile.Close();
>
> return bRet;
> }
>
> "Joseph M. Newcomer" wrote:
>
> > Are you using TCP/IP or UDP?
> >
> > Are you making sure that, if you are handling strings, that you insert a
terminating NUL
> > character after the characters received? For example, if you have a 1K
buffer, receive 4
> > bytes representing 4 8-bit characters, then you must put a NUL in [4] a
NUL character, or
> > whatever is seen there will be seen as part of the string.
> > joe
> >
> > On Tue, 10 Jan 2006 16:03:02 -0800, "Vinoj"
<Vinoj@xxxxxxxxxxxxxxxxxxxxxxxxx> wrote:
> >
> > >Hello,
> > >
> > >I have two programs that use async sockets. Occasionally, there is
garbage
> > >(extra bytes) being sent after data, thus confusing my finite state
machine.
> > >Is there a way to track everytime the send() is called? Any ideas on
why
> > >this could be happening?
> > >
> > >I don't know if it matters, but the sending side of the program is
written
> > >in C and the receiving side is MFC. Thanks.
> > >
> > >Vinoj
> > Joseph M. Newcomer [MVP]
> > email: newcomer@xxxxxxxxxxxx
> > Web: http://www.flounder.com
> > MVP Tips: http://www.flounder.com/mvp_tips.htm
> >


.



Relevant Pages

  • Re: CAsyncSocket and Send
    ... > The code you posted does not execute an "asynchronous" file transfer. ... > WSAGetLastErrorof WSAEWOULDBLOCK. ... which usually is less than a full buffer). ... On the receiving ...
    (microsoft.public.vc.mfc)
  • Re: pushing the envelope with sockets
    ... receiving on the socket they are received (upto the buffer size), you can even change what happens if the buffer runs full. ... int read = S.EndReceive; ... class AsyncReader: Reader ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Fundamentals question, is this how it works?
    ... Note the packet may be partially received when you get ... That is what i thought i was saying that it receives it all in a stream ... receving the buffer size each time. ... receiving that many bytes i then break and wait for the next set of data ...
    (microsoft.public.win32.programmer.networks)
  • Re: pushing the envelope with sockets
    ... so it would seem 2.0 does indeed buffer UDP. ... Using async I/O ... receiving on the socket they are received, ... Okay, so during *one* run, the cpu spent increases when input-data is ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Fundamentals question, is this how it works?
    ... processing packets after you are done with one. ... receving the buffer size each time. ... TCP is a stream-based protocol, which means that it ignores any attempt ... then the receiving side might get ...
    (microsoft.public.win32.programmer.networks)