Click to See Complete Forum and Search --> : CAsyncSocket OnReceive


tim24
February 12th, 2005, 04:36 PM
Hi all,
I have questions relate to How to receive all data inside
OnReceive() of a CAsyncSocket socket.

I know that it's illegal to call multiple times inside OnReceive.

But if I call only one time Receive().....how much buffer will i need to
declare and pass into Receive(buffer, SIZE);

if i declare
define SIZE=8000;
char buffer[SIZE]
then what happen if that socket get 10000 at that time ?


Thanks

NigelQ
February 12th, 2005, 09:55 PM
You could try using the IOCtl member function to determine the number of bytes that can be read at one time using the FIONREAD command parameter.

You could also call Receive multiple times waiting for the return value (bytes read) to equal something less than your buffer size (nBufLen param)

Hope this helps,

- Nigel

tim24
February 12th, 2005, 11:28 PM
Thanks for the idea

But i heard that we cannot call multiple times of Receive inside
OnReceive() and It's asyncsocket.

I will try to use FIONREAD to see if it works or not..

NigelQ
February 12th, 2005, 11:42 PM
It is possible, but depends heavily on the design. You are correct to avoid making multiple Receive calls inside the OnReceive handler wherever possible.

Hope this helps,

- Nigel

tim24
February 12th, 2005, 11:52 PM
Thanks.

I'd like to know what is the common design/approach if I want
to write a programX that will redirect data from programA(client) to programB(server).

I cannot touch programA and programB
I only responsible to write programX.

How many ways to handle that job (redirect data from A to B and B to A)
in an efficient way and fast performance (assume my program will be running under heavy/normal traffic)


Really appreciate for any help

Andreas Masur
February 13th, 2005, 04:27 AM
[ Moved thread ]

NigelQ
February 13th, 2005, 12:46 PM
Tim,

I'm not sure what part of the arrangement you are asking about.

If your ProgramX is communicating with the server, then it is a client of that server.

If your ProgramX is communicating with a client (and you are pretending to be the server) then you are the server to that client.

If this is the case, then you probably need a thread dedicated to being a client and another thread dedicated to being a server.

If the two threads need to communicate, you can post messages between the two for simplicity, therefore a thread with a message queue should work for you.

Are there other ways? Sure I guess, but a lot depends on how you want to implement things.

There are samples around that show client and server based communication. One such example is one the Microsoft site. In fact it is a pair of applications, named chatter and chatsvr. They can be found here (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vcsample/html/_sample_mfc_CHATTER.asp)

Although they show a simple chat type messaging system, all of the basics are there for a client/server architecture.

Note that the samples only transfer text messages, so if you want to sent binary information, you need to modify the code to do so (it's pretty simple from what I recall).

Hope this helps,

- Nigel

MikeAThon
February 14th, 2005, 10:29 AM
...But if I call only one time Receive().....how much buffer will i need to declare and pass into Receive(buffer, SIZE);

if i declare
define SIZE=8000;
char buffer[SIZE]
then what happen if that socket get 10000 at that time ?

There's no need to do anything tricky here. The Winsock stack is designed to work the way you expect it to, and will issue another OnReceive (FD_READ) call for the remaining 2000 bytes after you Receive() the first 8000. In particular, there's no need to call IOCtl with FIONREAD.

The documentation is reasonably clear on this point. Here's what MSDN says about the WSAAsyncSelect function, at http://msdn.microsoft.com/library/en-us/winsock/winsock/wsaasyncselect_2.asp (note that this refers to the Winsock 2 dll ):
The WS2_32.DLL will not continually flood an application with messages for a particular network event. Having successfully posted notification of a particular event to an application window, no further message(s) for that network event will be posted to the application window until the application makes the function call that implicitly reenables notification of that network event.

Event Reenabling function
FD_READ recv, recvfrom, WSARecv, or WSARecvFrom.
FD_WRITE send, sendto, WSASend, or WSASendTo.
FD_OOB recv, recvfrom, WSARecv, or WSARecvFrom.
FD_ACCEPT accept or WSAAccept unless the error code is WSATRY_AGAIN indicating that the condition function returned CF_DEFER.
FD_CONNECT None.
FD_CLOSE None.
FD_QOS WSAIoctl with command SIO_GET_QOS.
FD_GROUP_QOS Reserved. WSAIoctl with command SIO_GET_GROUP_QOS (reserved for future use with socket groups).
FD_ROUTING_INTERFACE_CHANGE WSAIoctl with command SIO_ROUTING_INTERFACE_CHANGE.
FD_ADDRESS_LIST_CHANGE WSAIoctl with command SIO_ADDRESS_LIST_CHANGE.

Any call to the reenabling routine, even one that fails, results in reenabling of message posting for the relevant event.

For FD_READ, FD_OOB, and FD_ACCEPT events, message posting is level-triggered. This means that if the reenabling routine is called and the relevant condition is still met after the call, a WSAAsyncSelect message is posted to the application. This allows an application to be event-driven and not be concerned with the amount of data that arrives at any one time. Consider the following sequence:

Network transport stack receives 100 bytes of data on socket s and causes Windows Sockets 2 to post an FD_READ message.
The application issues recv( s, buffptr, 50, 0) to read 50 bytes.
Another FD_READ message is posted because there is still data to be read.

With these semantics, an application need not read all available data in response to an FD_READ message—a single recv in response to each FD_READ message is appropriate. If an application issues multiple recv calls in response to a single FD_READ, it can receive multiple FD_READ messages. Such an application can require disabling FD_READ messages before starting the recv calls by calling WSAAsyncSelect with the FD_READ event not set.

That's alot to read, so I highlighted the best parts.

So, basically, within your OnReceive handler, one single call to Receive() will re-enable FD_READ notifications, and you will immediately get another FD_READ notification if your first call to Receive() did not retrieve all the data that Winsock wanted to give you.

Note that the above quoted section from the WSAAsyncSelect docs also explains part of the reason why it's "bad" to issue multiple calls to Receive() from within the OnReceive() handler.

Mike

MikeAThon
February 14th, 2005, 10:37 AM
...I'd like to know what is the common design/approach if I want
to write a programX that will redirect data from programA(client) to programB(server)....
It sounds like the work that an HTTP proxy server performs. Look at this article:

"HTTP Tunneling (HTTP Proxy Socket Client)" at http://www.codeguru.com/Cpp/I-N/internet/http/article.php/c6209/

Mike