The Internet Encyclopedia (Volume 3)

(coco) #1

P1: 50


Mayfield WL040/Bidgoli-Vol III-Ch-52 June 23, 2003 16:35 Char Count= 0


WINSOCKPROGRAMMING 641

argument to the thread function. Because the thread func-
tion needs to update the current number of clients dis-
played in the view, it needs access to the MFCCEditView
object. But—just as in the case of aCSocketobject—
the view object cannot be shared between threads; this is
the reason for the call toGetSafeHwnd,which returns
a safe handle for the view object.

Create the Worker Thread Procedure
Insert the implementation of the global functionServer-
ThreadProc shown as Listing 2 into the file MFC-
ServerView.cpp just above the implementation of
OnInitialUpdate. The purpose of this function is to
wait for a client connection, and once the connection has
been made, to serve date/time strings to the client once
each second. Further, after the connection has been made
the function starts another thread (using the same thread
function) so that other clients can be served simultane-
ously.

Listing 2:Thread procedure from example WinSock server
program.
(1) UINT ServerThreadProc(LPVOID pParam) {
(2) CSocket clientSock, serverSock;
(3)
(4) // Retrieve view ptr so messages can
be displayed.
(5) CWnd *pView = CWnd::FromHandle((HWND)
pParam);
(6)
(7) // Attach the global socket handle
to the local
(8) // listening socket object.
(9) serverSock.Attach(hSocket);
(10)
(11) // Wait for a client connection.
(12) if (!serverSock.Accept(clientSock)) {
(13) AfxGetMainWnd()-> MessageBox
("Accept Error");
(14) // Close the socket.
(15) serverSock.Close();
(16) // Return a non-zero code.
(17) return 1;
(18) }
(19)
(20) // Display the current num of
clients to the view.
(21) CString msg;
(22) msg.Format("Number of clients: %d",
++NumOfClients);
(23) pView->SetWindowText(msg);
(24)
(25) // Now the socket handle should be
detached from
(26) // from the listing socket object.
(27) serverSock.Detach();
(28)
(29) // After the Accept call unblocks,
begin another
(30) // thread to handle multiple
clients.

(31) AfxBeginThread(ServerThreadProc,
pParam);
(32)
(33) // Create a socket file and a
storing archive.
(34) CSocketFile sockFile(&clientSock);
(35) CArchive archiveSend(&sockFile,
CArchive::store);
(36) // Send the time once a second until
the client
(37) // connection terminates.
(38) TRY {
(39) time_t tTime;
(40) char buffer[64];
(41) while (1) {
(42) // Get current time from the
server machine.
(43) time(&tTime);
(44) // Format and send the server
time to the client.
(45) strcpy(buffer, ctime(&tTime));
(46) buffer[strlen(buffer)-1] = '\0';
(47) sockFile.Write(buffer, strlen
(buffer)+1);
(48) // Now wait a second...
(59) Sleep(1000);
(60) }
(51) }
(52) CATCH (CFileException, pEx) {
(53) // Communication was lost with
the client;
(54) // update the view.
(55) msg.Format("Number of clients: %d",
(56) --NumOfClients);
(57) pView->SetWindowText(msg);
(58) // close the client socket.
(59) clientSock.Close();
(60) }
(61) END_CATCH
(62)
(63) // Return success code.
(64) return 0;
(65) }

The first couple of actions taken inServerThread-
Procare there to recover the MFC objects from the han-
dles created in the main thread. Line 5 in Listing 2 re-
trieves the view from the handle that was passed as an
argument to the thread function. Line 9 attaches the lis-
tening socket (the handle of which is stored in the global
variablehSocket) to a localCSocketobject.
In line 12 the listening socket waits for a connection
from a client; as mentioned earlier, a call toAcceptis
a blocking call, so execution is suspended until a con-
nection is requested by a client. Once the call unblocks,
lines 21–23 update the view to reflect that another client
is being served. Line 27 detaches the listening socket
from the localCSocketobject in preparation for line
31, which starts another thread to accept another client
connection.
Lines 34–61 of Listing 2 do the actual serving
of strings to the client. First, lines 34–35 set up a
Free download pdf