📄 ch20.htm
字号:
// Continue on}else // Perform error handling here</PRE><P>At this point, the connecting application is connected to the second socket onthe listening application.</P><P><H3><A NAME="Heading5"></A>Sending and Receiving Messages</H3><P>Sending and receiving message through a socket connection gets slightly involved.Because you can use sockets to send any kind of data, and they don't care what thedata is, the functions to send and receive data expect to be passed a pointer toa generic buffer. For sending data, this buffer should contain the data to be sent.For receiving data, this buffer will have the received data copied into it. As longas you are sending and receiving strings and text, you can use fairly simple conversionsto and from CStrings with these buffers.</P><P>To send a message through a socket connection, you use the Send method. This methodrequires two parameters and has a third, optional parameter that can be used to controlhow the message is sent. The first parameter is a pointer to the buffer that containsthe data to be sent. If your message is in a CString variable, you can use the LPCTSTRoperator to pass the CString variable as the buffer. The second parameter is thelength of the buffer. The method returns the amount of data that was sent to theother application. If an error occurs, the Send function returns SOCKET_ERROR. Youcan use the Send method as follows:</P><P><PRE>CString strMyMessage;int iLen;int iAmtSent;...iLen = strMyMessage.GetLength();iAmtSent = m_sMySocket.Send(LPCTSTR(strMyMessage), iLen);if (iAmtSent == SOCKET_ERROR){ // Do some error handling here}else{ // Everything's fine}</PRE><P>When data is available to be received from the other application, an event istriggered on the receiving application. This lets your application know that it canreceive and process the message. To get the message, the Receive method must be called.This method takes the same parameters as the Send method with a slight difference.The first parameter is a pointer to a buffer into which the message may be copied.The second parameter is the size of the buffer. This tells the socket how much datato copy (in case more is received than will fit into the buffer). Like the Send method,the Receive method will return the amount that was copied into the buffer. If anerror occurs, the Receive method also returns SOCKET_ERROR. If the message your applicationis receiving is a text message, it can be copied directly into a CString variable.This allows you to use the Receive method as follows:</P><P><PRE>char *pBuf = new char[1025];int iBufSize = 1024;int iRcvd;CString strRecvd;iRcvd = m_sMySocket.Receive(pBuf, iBufSize);if (iRcvd == SOCKET_ERROR){ // Do some error handling here}else{ pBuf[iRcvd] = NULL; strRecvd = pBuf; // Continue processing the message}</PRE><BLOCKQUOTE> <P><HR><STRONG>TIP:</STRONG> When receiving text messages, it's always a good idea to place a NULL in the buffer position just after the last character received, as in the preceding example. There may be garbage characters in the buffer that your application might interpret as part of the message if you don't add the NULL to truncate the string.<HR> <P><HR><STRONG>NOTE:</STRONG> The Close function is one of the few CAsyncSocket methods that does not return any status code. For all the previous member functions that we have examined, you can capture the return value to determine if an error has occurred.<HR></BLOCKQUOTE><H3><A NAME="Heading6"></A>Closing the Connection</H3><P>Once your application has finished all of its communications with the other application,it can close the connection by calling the Close method. The Close method doesn'ttake any parameters, and you use it as follows:</P><P><PRE>m_sMySocket.Close();</PRE><H3><A NAME="Heading7"></A>Socket Events</H3><P>The primary reason that you create your own descendent class of CAsyncSocket isthat you want to capture the events that are triggered when messages are received,connections are completed, and so on. The CAsyncSocket class has a series of functionsthat are called for each of these various events. These functions all use the samedefinition--the function name is the only difference--and they are intended to beoverridden in descendent classes. All of these functions are declared as protectedmembers of the CAsyncSocket class and probably should be declared as protected inyour descendent classes. The functions all have a single integer parameter, whichis an error code that should be checked to make sure that no error has occurred.Table 20.1 lists these event functions and the events they signal.</P><P><H4>TABLE 20.1. CAsyncSocket OVERRIDABLE EVENT-NOTIFICATION FUNCTIONS.</H4><P><TABLE BORDER="1"> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT"><I>Function</I></TD> <TD ALIGN="LEFT"><I>Event Description</I></TD> </TR> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT">OnAccept </TD> <TD ALIGN="LEFT">This function is called on a listening socket to signal that a connection request from another application is waiting to be accepted. </TD> </TR> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT">OnClose </TD> <TD ALIGN="LEFT">This function is called on a socket to signal that the application on the other end of the connection has closed its socket or that the connection has been lost. This should be followed by closing the socket that received this notification. </TD> </TR> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT">OnConnect </TD> <TD ALIGN="LEFT">This function is called on a socket to signal that the connection with another application has been completed and that the application can now send and receive messages through the socket. </TD> </TR> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT">OnReceive </TD> <TD ALIGN="LEFT">This function is called to signal that data has been received through the socket connection and that the data is ready to be retrieved by calling the Receive function. </TD> </TR> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT">OnSend </TD> <TD ALIGN="LEFT">This function is called to signal that the socket is ready and available for sending data. This function is called right after the connection has been completed. Usually, the other time that this function is called is when your application has passed the Send function more data than can be sent in a single packet. In this case, this is a signal that all of the data has been sent, and the application can send the next buffer-full of data. </TD> </TR></TABLE><H3><A NAME="Heading8"></A>Detecting Errors</H3><P>Whenever any of the CAsyncSocket member functions return an error, either FALSEfor most functions or SOCKET_ERROR on the Send and Receive functions, you can callthe GetLastError method to get the error code. This function returns only error codes,and you have to look up the translation yourself. All the Winsock error codes aredefined with constants, so you can use the constants in your code to determine theerror message to display for the user, if any. You can use the GetLastError functionas follows:</P><P><PRE>int iErrCode;iErrCode = m_sMySocket.GetLastError();switch (iErrCode){case WASNOTINITIALISED:...}</PRE><H2><A NAME="Heading9"></A>Building a Networked Application</H2><P>For the sample application that you will build today, you'll create a simple dialogapplication that can function as either the client or server in a Winsock connection.This will allow you to run two copies of the sample application, one for each endof the connection, on the same computer or to copy the application to another computerso that you can run the two copies on separate computers and see how you can passmessages across a network. Once the application has established a connection withanother application, you will be able to enter text messages and send them to theother application. When the message has been sent, it will be added to a list ofmessages sent. Each message that is received will be copied into another list ofall messages received. This will allow you to see the complete list of what is sentand received. It will also allow you to compare what one copy of the applicationhas sent and what the other has received. (The two lists should be the same.)</P><P><H3><A NAME="Heading10"></A>Creating the Application Shell</H3><P>For today's sample application, just to keep things simple, you'll create a dialog-styleapplication. Everything that you are doing in today's application can be done inan SDI or MDI application just as easily as with a dialog-style application. By usinga dialog-style application today, we are getting everything that might distract fromthe basic socket functionality (such as questions about whether the socket variablebelongs in the document or view class, how much of the application functionalitybelongs in which of these two classes, and so on) away from the sample application.</P><P>To start today's sample application, create a new MFC AppWizard project, givingthe project a suitable name, such as Sock. On the first step of the AppWizard, specifythat the application will be a dialog-based application. On the second step of theAppWizard, specify that the application should include support for Windows Sockets,as in Figure 20.3. You can accept the default settings for the rest of the optionsin the AppWizard.</P><P><H3><B>Window Layout and Startup Functionality</B></H3><P>Once you create your application shell, you can lay out the main dialog for yourapplication. On this dialog, you'll need a set of radio buttons to specify whetherthe application is running as the client or server. You'll also need a couple ofedit boxes for the computer name and port that the server will be listening on. Next,you'll need a command button to start the application listening on the socket oropening the connection to the server, and a button to close the connection. You'llalso need an edit box for entering the message to be sent to the other applicationand a button to send the message. Finally, you'll need a couple of list boxes intowhich you can add each of the messages sent and received. Place all these controlson the dialog, as shown in Figure 20.4, setting all of the control properties asspecified in Table 20.2.</P><P><A HREF="javascript:popUp('20fig03.gif')"><B>FIGURE 20.3.</B></A><B> </B><I>Includingsockets support.</I></P><P><A HREF="javascript:popUp('20fig04.gif')"><B>FIGURE 20.4.</B></A><B> </B><I>Themain dialog layout.</I></P><P><I></I><H4>TABLE 20.2. CONTROL PROPERTY SETTINGS.</H4><P><TABLE BORDER="1"> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT"><I>Object</I></TD> <TD ALIGN="LEFT"><I>Property</I></TD> <TD ALIGN="LEFT"><I>Setting</I></TD> </TR> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT">Group Box </TD> <TD ALIGN="LEFT">ID </TD> <TD ALIGN="LEFT">IDC_STATICTYPE </TD> </TR> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT"> <P> </TD> <TD ALIGN="LEFT">Caption </TD> <TD ALIGN="LEFT">Socket Type </TD> </TR> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT">Radio Button </TD> <TD ALIGN="LEFT">ID </TD> <TD ALIGN="LEFT">IDC_RCLIENT </TD> </TR> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT"> <P> </TD> <TD ALIGN="LEFT">Caption </TD> <TD ALIGN="LEFT">&Client </TD> </TR> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT"> <P> </TD> <TD ALIGN="LEFT">Group </TD> <TD ALIGN="LEFT">Checked </TD> </TR> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT">Radio Button </TD> <TD ALIGN="LEFT">ID </TD> <TD ALIGN="LEFT">IDC_RSERVER </TD> </TR> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT"> <P> </TD> <TD ALIGN="LEFT">Caption </TD> <TD ALIGN="LEFT">&Server </TD> </TR> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT">Static Text </TD> <TD ALIGN="LEFT">ID </TD> <TD ALIGN="LEFT">IDC_STATICNAME </TD> </TR> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT"> <P> </TD> <TD ALIGN="LEFT">Caption </TD> <TD ALIGN="LEFT">Server &Name: </TD> </TR> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT">Edit Box </TD> <TD ALIGN="LEFT">ID </TD> <TD ALIGN="LEFT">IDC_ESERVNAME </TD> </TR> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT">Static Text </TD> <TD ALIGN="LEFT">ID </TD> <TD ALIGN="LEFT">IDC_STATICPORT </TD> </TR> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT"> <P> </TD> <TD ALIGN="LEFT">Caption </TD> <TD ALIGN="LEFT">Server &Port: </TD> </TR> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT">Edit Box </TD> <TD ALIGN="LEFT">ID </TD> <TD ALIGN="LEFT">IDC_ESERVPORT </TD> </TR> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT">Command Button </TD> <TD ALIGN="LEFT">ID </TD> <TD ALIGN="LEFT">IDC_BCONNECT </TD> </TR> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT"> <P> </TD> <TD ALIGN="LEFT">Caption </TD> <TD ALIGN="LEFT">C&onnect </TD> </TR> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT">Command Button </TD> <TD ALIGN="LEFT">ID </TD> <TD ALIGN="LEFT">IDC_BCLOSE </TD> </TR> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT"> <P> </TD> <TD ALIGN="LEFT">Caption </TD> <TD ALIGN="LEFT">C&lose </TD> </TR> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT"> <P> </TD> <TD ALIGN="LEFT">Disabled </TD> <TD ALIGN="LEFT">Checked </TD> </TR> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT">Static Text </TD> <TD ALIGN="LEFT">ID </TD> <TD ALIGN="LEFT">IDC_STATICMSG </TD> </TR> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT"> <P> </TD> <TD ALIGN="LEFT">Caption </TD> <TD ALIGN="LEFT">&Message: </TD> </TR> <TR ALIGN="LEFT" VALIGN="TOP"> <TD ALIGN="LEFT"> <P>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -