Click to See Complete Forum and Search --> : Winsock: Why is MFC considered bad
Mathew Joy
February 25th, 2004, 12:02 AM
Let me start by stating a few points to why MFC (CAsyncSocket & CSocket) winsock programming is bad.
CAsyncSocket is the basic socket wrapper. It is asynchronous in nature. But this wrapper class has a couple of problems, which is one of the reasons to why this is in efficient when writing a server. One of the most visible flaw is that, CAsyncSocket communicates using window messages but your class cannot derive from both CAsyncSocket and CWnd class because of a base class conflict. Instead, CAsyncSocket creates a separate window to handle these messages. This is a design flaw. Second, it has a synchronous DNS lookup, that means a slow DNS server can cause a delay for a long time.
Comming to CSocket, it is from bad to worse. Though it is derived from an asynchronous class, CSocket is ment to be synchronous (blocking). So it fakes blocking I/O. Now the problem with this is, while blocking (actually only faking), the message pump is working, which causes a message to trigger yet another call to CSocket object. This happens becase the base class keeps sending window messages. Another problem is CSocket tends to crash in some situations (non-trivial). Speeking in terms of OOP, CSocket breaks an important OOP desing. The "is a" rule. How can you say "is a" when the base class is asynchronous while the derived class is synchronous.
These are some of the visible and serious problems.
So what is your option? Use APIs. The one that is just needed (necessary and sufficient) for your program. I would recommend choosing from the following IO models
:) Blocking IO (Easier and much better choice than CSocket)
:) WSAAsyncSelect()/WSAEventSelect() (Though simillar WSAEventSelect() has better performance)
:) IOCP (best for high scalable and high performance server)
Though there are other IO models you can narrow it down to these three. The design and coding complexity goes in the increasing order of magnitude down the order.
<Edit: few words added>
MikeAThon
February 25th, 2004, 12:41 AM
Originally posted by Mathew Joy
Let me start by stating a few points to why MFC (CAsyncSocket & CSocket) winsock programming is bad.
I couldn't disagree with you more. There are limitations to these classes, but so long as they are understood, they're fine. CSocket isn't great, but if used like a blocking socket (I know it's not really a blocking socket), then it's just fine. And CAsyncSocket is a fairly close wrapper to the Winsock API, and is fine as it is.
One of the most visible flaw is that ... your class cannot derive from both CAsyncSocket and CWnd class because of a base class conflict.
That's not the reason why you can't derive from both CWnd and CAsyncSocket. The real reason is a defect common to ALL MFC classes -- they don't support multiple inheritance (MI) very well, at least not when one of the base classes is derived from CObject (and both CAsyncSocket and CWnd are derived from CObject). See "TN016: Using C++ Multiple Inheritance with MFC", at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vcmfc98/html/_mfcnotes_tn016.asp
Instead, CAsyncSocket creates a separate window to handle these messages.
That's plain wrong. It's true that CSocket does this, but not CAsyncSocket.
Second, it has a synchronous DNS lookup, that means a slow DNS server can cause a delay for a long time.
That's true and well-documented.
Comming to CSocket, it is from bad to worse. Though it is derived from an asynchronous class, CSocket is ment to be synchronous (blocking). So it fakes blocking I/O. Now the problem with this is, while blocking (actually only faking), the message pump is working, which causes a message to trigger yet another call to CSocket object.
I don't know what you mean by "which causes a message to trigger yet another call to CSocket object", so I won't comment, but the rest of this seems true. At the same time, CSocket conveniently supplies a special virtual function, CSocket::OnMessagePending(), nbot found in the base class, which is called while the socket is pumping Windows messages to give you an opportunity to deal with messages of interest to your application. One example of how this can be used is in the widespread CTimeoutSocket, which is a convenient derived class that times out (such as after 30 seconds) after waiting for a response, rather than blocking forever.
Another problem is CSocket tends to crash in some situations (non-trivial).
Please provide an example
Speeking in terms of OOP, CSocket breaks an important OOP desing. The "is a" rule. How can you say "is a" when the base class is asynchronous while the derived class is synchronous.
That's true.
So what is your option? Use APIs. The one that is just needed (necessary and sufficient) for your program. I would recommend choosing from the IO models
Despite my defense of the MFC socket classes, I agree that the Winsock API is better. In particular, one significant drawback to the MFC socket classes is their reliance on a message pump, which makes them difficult to use in a worker thread. Event-based sockets don't have this limitation.
Regards,
Mike
Andreas Masur
February 25th, 2004, 04:30 PM
And to provide more reference to the topic...take a look at the following (http://tangentsoft.net/wskfaq/articles/csocket.html)... :cool:
Mathew Joy
February 26th, 2004, 01:34 AM
Regret the delay. Our gateway was down.
Clarification: Read my post as when writing a server
Originally posted by MikeAThon
I couldn't disagree with you more.
Neither can I.
There are limitations to these classes, but so long as they are understood, they're fine.
You are right. If you understand the limitations then the MFC socket is usable. But it doesn't becomes useful.
CSocket isn't great, but if used like a blocking socket (I know it's not really a blocking socket), then it's just fine. Consider this. If you want to use CSokcet your class called mysock(say) should derive like this. mysock->CSocket->CAsyncSocket->CObject. Why carry this baggy aroud if you can use Blocking sockets apis straight, which is dead easy to program? Besides CSocket has bugs and flaws. CSocket doesn't give the performace a blocking server can give. And CAsyncSocket is a fairly close wrapper to the Winsock API, and is fine as it is.As fine as what is? Being close or not is not the question. You can't simply use Winsock API and say I have created a scalable server. You have to use different models that deal with IO. So instead of simply wrapping it should act 'intelligently'.
That's not the reason why you can't derive from both CWnd and CAsyncSocket...I'm not sure about why you can't derive, but what I said, I read in one expert comment.
That's plain wrong. It's true that CSocket does this, but not CAsyncSocket.Where did you get this idea from? and how does CAsyncSocket communicate using window messages without creating a window. MS itself has clarified this in NGs. The CAsyncSocket creates hidden window named "Socket Notification Sink" when Create() method is called to process WM_SOCKET_NOTIFY message.
That's true and well-documented.Doesn't mean that I cannot specify this when explaining the drawback of MFC.
Please provide an exampleMFC sockets is not recomented in services. It may cause more problem while using in ATL. (Some of the immediate ex. that come to my mind) Cannot specify any ex for CSocket in particular, but is reported
Despite my defense of the MFC socket classes, I agree that the Winsock API is better. In particular, one significant drawback to the MFC socket classes is their reliance on a message pump, which makes them difficult to use in a worker thread. Event-based sockets don't have this limitation.Writing a server is all about scalabaility, performance, response time etc. There is no way that you can attain this using MFC. It is very well known and agreed (among network programmers and experts) that MFC fares badly as a socket wrapper class even if there is not bugs or flaws. The major reason is something to do with the nature of using winsockets to build a server. What you can do is make your own wrapper class that meets your need. My suggestion is, if you wan't to use MFC badly use CAsyncSocket rather than CSocket.
PS: Most of what I said in my two posts can be found if you can do a bit of research on the net. The best start is on NGs (google groups). I may not answer any further request for clarification if the reader cannot do that part
codeguru.com
Copyright 2007 Jupitermedia Corporation All Rights Reserved.