Multithreading is the best solution—albeit a non-trivial one.
First you write your thread function(s). Then you start a thread with a call to Win32 giving it the name of the function to run and a pointer to a block of data to pass to the function (it's declared as void* so that you can cast it to whatever struct type you have defined). There are a number of API functions you could call: the official one is CreateThread() and the traditional one is _beginthread().
All threads in a process can access global data, but you need to control that access so that one thread is not changing common data while another is reading it. This controlling is called "thread synchronization". It is a very important subject to learn if you are going to be doing any multithread or multiprocess operations. Accessing of uch data is often placed in a "critical section" of the code and certain data structures called "mutexes" (mutual exclusion) are employed to keep one thread from executing its critical section as long as another thread is in its. If you are not careful, then you could have two threads waiting for access to be freed to resources that the other is holding; this "race condition" will prevent your program from working.
I just gave you a number of keywords to research. You must understand what they mean and what their consequences are in order for you to use mulithreading. BTW, multithreaded programs are also notoriously difficult to debug.
OK, here's how I understand the basic multihreaded server would need to be organized:
The main thread (every process has one) would be run at startup, and would continue to run the user interface, system logging, etc. . After it has created the listening socket, it would start the accept-thread. The accept-thread would call accept()—and spend most of its time blocked there. When accept() returns with a new socket, this thread would then create and start the thread(s) for handling that client. Next, it would call accept()—waiting for the next client. If accept() returns an error, then that error would need to be handled. The client thread would handle the session with the client. When the client disconnects, the thread would close.
For handling a client, you might need more than one thread; i.e., to be able to keep the blocking on recv() from preventing you from sending, you would need one thread for receiving and a second for sending.
---
Now, an alternative to multithreading would be to use the select() function. You call select with a set of the sockets you expect to read from and a timeout value and it returns the number of sockets that are read to be read. You then read from the ones that are pending (and which therefore will not block); if none were pending (select() returned zero), then it returns after the timeout has elapsed. In either case, your application can then perform whatever other functions it needs to, including user I/O, and then it calls select() again.
If you are not yet up on multithreading, then you should at least take a good look at select().
Of course, there is overhead involved in either of the two methods being considered. I understand that the overhead of select() increases somewhat as the number of sockets increases—as I've heard, servers using this approach prefer using poll() instead of select().
Note: I don't know if poll() is available under Winsock. Besides, I'm not sure how that compares with the increase (in overhead) using multithreading. Nevertheless, this is an issue that you will need to look into eventually.
_____________________________
NEED CODE SAMPLES OF MULTITHREAD SERVER?
---
Apache is open-source; so, that should serve as an example. Check out the information on the "Using Apache With Microsoft Windows" page, http://httpd.apache.org/docs/windows.html, it says:
Quote:
The source code is available in the -src.msi distribution, or from the distribution directory as a .zip file. If you plan on compiling Apache yourself, there is no need to install either .msi package. The .zip file contains only source code, with MS-DOS line endings (that is cr/lf line endings, instead of the single lf used for Unix files distributed in .tar.gz or .tar.Z archives.) While the source is also available as a .tar.gz .tar.Z archive, these contain unix lf line endings that cause grief for Windows users. To use those archives, you must convert at least the .mak and .dsp files to have DOS line endings before MSVC can understand them. Please stick with the .zip file to spare yourself the headache.
---
If you go to that page, the first paragraph I quoted above (third paragraph in the "Downloading Apache for Windows" section) contains the link to the distribution directory.
Yes, I know that 9.5 MB (compressed) is a lot. You could Google about for a smaller example if you'd prefer. When you do, keep in mind that you must specify "Win32". Undoubtedly most multithreaded servers you'll find will be for UNIX or Linux, which use POSIX threads via pthreads. pthreads involves many of the same principles as Win32 multithreading, but the function calls and data structures are very different.
--------------------------------------------------
CAVEAT: IF YOU ARE USING VISUAL BASIC...
Ok, I have found out that despite what MSDN says, you cant pass the RequestID accross threads in Visual Basic.
However, here is how I resolved it....I used SocketWrench!
SocketWrench is like Winsock, but it's 50x better, and it supports multithreading. I just thought I would post my findings incase anyone else was wondering how you do multithreading with Winsock.
---
Also check out: Multithreading with Winsock (it's a short paragraph): http://www.vbip.com/comment.asp?146