Re: CAsyncSocket and Send
- From: "Vinoj" <Vinoj@xxxxxxxxxxxxxxxxxxxxxxxxx>
- Date: Thu, 12 Jan 2006 09:45:03 -0800
Thanks for the advice. I'll try taking it apart.
"Michael K. O'Neill" wrote:
> "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
> > >
>
>
>
.
- References:
- Re: CAsyncSocket and Send
- From: Joseph M . Newcomer
- Re: CAsyncSocket and Send
- From: Vinoj
- Re: CAsyncSocket and Send
- From: Michael K. O'Neill
- Re: CAsyncSocket and Send
- Prev by Date: Re: How to send WM_KEYDOWN message to focused window
- Next by Date: ADO recordset command text vs command
- Previous by thread: Re: CAsyncSocket and Send
- Next by thread: Re: CAsyncSocket and Send
- Index(es):
Relevant Pages
|