Networking and Network Programming 2 TCP/IP phần 7 pptx

33 286 1
Networking and Network Programming 2 TCP/IP phần 7 pptx

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

Chapter 11 ■ CDatagramSocket 205 p2v6 Prog. WinSock #30594-1 tullis 11.14.94 CH11 LP #3 11 11 CDatagramSocket CDatagramSocket p2v6 Prog. WinSock #30594-1 tullis 11.14.94 CH11 LP #3 Part III ■ WinSock Class Library 206 This chapter discusses the CDatagramSocket class. This class simplifies an application’s interaction with a datagram socket. This class is responsible for creating a datagram socket, optionally binding the socket to a name, sending and receiving data, and destroying the socket. The class declaration is as follows: ///////////////////////////////////////////////////////////////////////////// // CDatagramSocket // class CDatagramSocket : public CWnd { private: CWnd *m_pParentWnd; // window to receive event notification UINT m_uMsg; // message to send to m_pParentWnd on event SOCKET m_s; // socket handle SOCKADDR_IN m_sinLocal; // name bound to socket m_s int m_nLastError; // last WinSock error BOOL m_bServer; // TRUE if socket m_s is bound to a name CPtrList m_listWrite; // data waiting to be sent CPtrList m_listRead; // data read public: CDatagramSocket(CWnd *pParentWnd, UINT uMsg); virtual ~CDatagramSocket(); int CreateSocket(int nLocalPort); int CreateSocket(LPSTR pszLocalService = NULL); int DestroySocket(); int Write(int nLen, LPVOID pData, LPSTR pszRemoteName, int nRemotePort); int Write(int nLen, LPVOID pData, LPSTR pszRemoteName, LPSTR pszRemoteService); int Write(int nLen, LPVOID pData, LPSOCKADDR_IN psinRemote); LPVOID Read(LPINT pnLen, LPSOCKADDR_IN psinRemote = NULL); int LastError() { return m_nLastError; } private: void InitVars(BOOL bInitLastError = TRUE); LONG HandleRead(WPARAM wParam, LPARAM lParam); LONG HandleWrite(WPARAM wParam, LPARAM lParam); // message map functions protected: //{{AFX_MSG(CStreamSocket) //}}AFX_MSG LONG OnWinSockEvent(WPARAM wParam, LPARAM lParam); DECLARE_MESSAGE_MAP() }; The class contains several private member variables that are inaccessible outside of the class implementation. Of particular interest are the m_listWrite and m_listRead mem- ber variables. These CPtrObject-derived objects maintain pointers to the incoming and outgoing data. The data maintained by these lists has the following structure: // structure used for datagram socket read/write queue typedef struct tagDATAGRAMDATA { Chapter 11 ■ CDatagramSocket 207 p2v6 Prog. WinSock #30594-1 tullis 11.14.94 CH11 LP #3 LPVOID pData; int nLen; SOCKADDR_IN sin; } DATAGRAMDATA, FAR * LPDATAGRAMDATA; CDatagramSocket Constructor The constructor for the CDatagramSocket object initializes the class’ member variables. The m_pParentWnd variable is the window object that’s creating this datagram socket object. This parameter is required because the CDatagramSocket object uses Windows messaging to communicate certain status information back to the object’s user. Simi- larly, the m_uMsg variable is the actual Windows message that m_pParentWnd receives when the datagram socket needs to notify the application of certain information. The class’ constructor looks like: ///////////////////////////////////////////////////////////////////////////// // CDatagramSocket constructor // // Constructs the CDatagramSocket object. Initializes member variables // CDatagramSocket::CDatagramSocket(CWnd *pParentWnd, UINT uMsg) { // initialize member variables m_pParentWnd = pParentWnd; ASSERT(m_pParentWnd != NULL); m_uMsg = uMsg; ASSERT(m_uMsg != 0); InitVars(); } CDatagramSocket::InitVars() The InitVars() member function initializes several private member variables. Its imple- mentation looks like the following: ///////////////////////////////////////////////////////////////////////////// // CDatagramSocket::InitVars() // // Initialize class member variables. // void CDatagramSocket::InitVars(BOOL bInitLastError/*= TRUE*/) { if (bInitLastError) m_nLastError = 0; m_s = INVALID_SOCKET; memset(&m_sinLocal, 0, sizeof(m_sinLocal)); m_bServer = FALSE; } p2v6 Prog. WinSock #30594-1 tullis 11.14.94 CH11 LP #3 Part III ■ WinSock Class Library 208 CDatagramSocket::CreateSocket() The CreateSocket() member function creates a hidden window that’s used for WinSock messages (that is, FD_READ and FD_WRITE). This function also creates a datagram socket and optionally binds the socket to a name. There are two implementations of the CreateSocket() member function. One implementation takes an integer parameter representing the port number, in host byte order, that should be bound to the socket. The other version of CreateSocket() accepts a string containing the numerical port number or service name to bind to the socket, or NULL. If NULL is specified, or if the function is called with no parameter at all, the socket is not bound to a name. Generally speaking, the parameter is specified only for server type sockets. The version of CreateSocket() that accepts an integer port number simply converts the integer into a string and calls the other version of CreateSocket(). It’s implemented as follows: ///////////////////////////////////////////////////////////////////////////// // CDatagramSocket::CreateSocket() // // Create a hidden window that will receive asynchronous messages // from WinSock. Also creates a socket and optionally binds it to // a name if the socket is a server socket. // // This version of the CreateSocket() function takes a // port number, in host order, as input. A port number // should only be specified if the socket is to be bound // to a certain port. If you don’t care which port is // assigned to the socket, just call CreateSocket() without // any parameter, causing CreateSocket(NULL) to be called. // int CDatagramSocket::CreateSocket(int nLocalPort) { // if this version of the function is being called, // a valid port number must be specified if (nLocalPort <= 0) return CWINSOCK_PROGRAMMING_ERROR; // convert the port number into a string and // call the version of CreateSocket() which // accepts a string char pszLocalService[18]; _itoa(nLocalPort, pszLocalService, 10); return CreateSocket(pszLocalService); } The version of CreateSocket() that accepts a string port number or service name is imple- mented in the code that follows. If the datagram socket need not be bound to a specific port number or service name, simply call this function with no parameter. The C++ default argument feature will pass NULL to the function, triggering CreateSocket() to not bind the socket. Chapter 11 ■ CDatagramSocket 209 p2v6 Prog. WinSock #30594-1 tullis 11.14.94 CH11 LP #3 ///////////////////////////////////////////////////////////////////////////// // CDatagramSocket::CreateSocket() // // Create a hidden window that will receive asynchronous messages // from WinSock. Also creates a socket and optionally binds it to // a name if the socket is a server socket. // // This version of the CreateSocket() function takes a // string containing a service name or port number. // A parameter should only be specified if the socket is to be // bound to a certain port. If you don’t care which port is // assigned to the socket, just call CreateSocket() without // any parameter, causing CreateSocket(NULL) to be called. // int CDatagramSocket::CreateSocket(LPSTR pszLocalService/*= NULL*/) { int nStatus = CWINSOCK_NOERROR; while (1) { // Make sure the socket isn’t already created. // If the socket handle is valid, return from this // function right away so the existing parameters of // the object are not tampered with. if (m_s != INVALID_SOCKET) return CWINSOCK_PROGRAMMING_ERROR; InitVars(); // create the hidden window RECT rect; rect.left = 0; rect.top = 0; rect.right = 100; rect.bottom = 100; if (Create(NULL, NULL, WS_OVERLAPPEDWINDOW, rect, m_pParentWnd, 0) == 0) { nStatus = CWINSOCK_WINDOWS_ERROR; break; } // create the socket m_s = socket(PF_INET, SOCK_DGRAM, 0); if (m_s == INVALID_SOCKET) { m_nLastError = WSAGetLastError(); nStatus = CWINSOCK_WINSOCK_ERROR; DestroyWindow(); break; } // If pszLocalService is not NULL, this is a server socket // that will accept data on the specified port. if (pszLocalService != NULL) { // this socket is bound to a port number // so set the server flag m_bServer = TRUE; p2v6 Prog. WinSock #30594-1 tullis 11.14.94 CH11 LP #3 Part III ■ WinSock Class Library 210 // assign the address family m_sinLocal.sin_family = AF_INET; // assign the service port (may have to do a database lookup // if a service port number was not specified) m_sinLocal.sin_port = htons(atoi(pszLocalService)); if (m_sinLocal.sin_port == 0) { LPSERVENT pSent = getservbyname(pszLocalService, “udp”); if (pSent == NULL) { m_nLastError = WSAGetLastError(); nStatus = CWINSOCK_WINSOCK_ERROR; closesocket(m_s); DestroyWindow(); break; } m_sinLocal.sin_port = pSent–>s_port; } // assign the IP address m_sinLocal.sin_addr.s_addr = htonl(INADDR_ANY); // bind the server socket to the name containing the port if (bind(m_s, (LPSOCKADDR)&m_sinLocal, sizeof(m_sinLocal)) == SOCKET_ERROR) { m_nLastError = WSAGetLastError(); nStatus = CWINSOCK_WINSOCK_ERROR; closesocket(m_s); DestroyWindow(); break; } } // start asynchronous event notification long lEvent = FD_READ | FD_WRITE; if (WSAAsyncSelect(m_s, m_hWnd, CWINSOCK_EVENT_NOTIFICATION, lEvent) == SOCKET_ERROR) { m_nLastError = WSAGetLastError(); nStatus = CWINSOCK_WINSOCK_ERROR; closesocket(m_s); DestroySocket(); break; } break; } // if anything failed in this function, set the // socket variables appropriately if (nStatus != CWINSOCK_NOERROR) InitVars(FALSE); return nStatus; } Chapter 11 ■ CDatagramSocket 211 p2v6 Prog. WinSock #30594-1 tullis 11.14.94 CH11 LP #3 CDatagramSocket::Write() The Write() member function writes data to the specified destination host and port. The data is not immediately sent out the socket, though. Instead, the data, its length, and the data’s destination address are added to the write queue. The data is not sent until the datagram socket receives the FD_WRITE message from the WinSock subsystem, notifying it that sending is now possible. Because the data is not sent immediately, the data specified by the data pointer must not be deallocated or reused until the window that owns the datagram socket receives the m_uMsg message with wParam set to CWINSOCK_DONE_WRITING or CWINSOCK_ERROR_WRITING. When this message is received by the application window, lParam is the pointer to the data sent. At this point, the data specified by the pointer can be freed or reused. If the Write() function fails immediately, denoted by the function returning something other than CWINSOCK_NOERROR, the data pointer may be freed or reused (the m_uMsg write message will never be received for this data pointer). There are three implementations of the Write() member function. All three functions have parameters that specify the number of bytes to send and a pointer to the data. The remaining function parameters vary depending on how you call Write(). Write() re- turns CWINSOCK_NOERROR on success. One implementation takes a string containing the dotted-decimal IP address of the destination or the destination host name, and an integer parameter representing the port number, in host byte order. This version of Write() simply converts the integer to a string and calls another version of the function that’s designed to accept a string con- taining the port number or service name. ///////////////////////////////////////////////////////////////////////////// // CDatagramSocket::Write() // // Write data to the socket specified by the name and port. // // This version of the Write() function takes an integer // representing the length of the data to send, a pointer // to the data to send, a pointer to a string representing // the host name to send the data to, and an integer // representing the port number to send to. // // The data pointed to by pData must remain valid until either // the Write() function returns with an error, or the // write’s completion is notified by the m_uMsg being sent // to the window that owns this datagram object with wParam set // to CWINSOCK_DONE_WRITING or CWINSOCK_ERROR_WRITING. // int CDatagramSocket::Write(int nLen, LPVOID pData, LPSTR pszRemoteName, int nRemotePort) p2v6 Prog. WinSock #30594-1 tullis 11.14.94 CH11 LP #3 Part III ■ WinSock Class Library 212 { // convert the port number into a string and // call the version of Write() which accepts // a string service name or number char pszRemoteService[18]; _itoa(nRemotePort, pszRemoteService, 10); return Write(nLen, pData, pszRemoteName, pszRemoteService); } The second implementation of Write() takes a string containing the dotted-decimal IP address of the destination or the destination host name, and a string containing either a port number or service name. This version of Write() converts the two strings into a SOCKADDR_IN Internet address structure and calls another version of the Write() func- tion. ///////////////////////////////////////////////////////////////////////////// // CDatagramSocket::Write() // // Write data to the socket specified by the name and service // name or number. // // This version of the Write() function takes an integer // representing the length of the data to send, a pointer // to the data to send, a pointer to a string representing // the host name to send the data to, and a string representing // the service name or port number to send the data to. // // The data pointed to by pData must remain valid until either // the Write() function returns with an error, or the // write’s completion is notified by the m_uMsg being sent // to the window that owns this datagram object with wParam set // to CWINSOCK_DONE_WRITING or CWINSOCK_ERROR_WRITING. // int CDatagramSocket::Write(int nLen, LPVOID pData, LPSTR pszRemoteName, LPSTR pszRemoteService) { int nStatus = CWINSOCK_NOERROR; // error status LPHOSTENT pHent; // pointer to host entry structure LPSERVENT pSent; // pointer to service entry structure SOCKADDR_IN sinRemote; // Internet address of destination while (1) { // assign the address family sinRemote.sin_family = AF_INET; // assign the service port (may have to do a database lookup // if a service port number was not specified) sinRemote.sin_port = htons(atoi(pszRemoteService)); if (sinRemote.sin_port == 0) { pSent = getservbyname(pszRemoteService, “udp”); if (pSent == NULL) { m_nLastError = WSAGetLastError(); nStatus = CWINSOCK_WINSOCK_ERROR; break; Chapter 11 ■ CDatagramSocket 213 p2v6 Prog. WinSock #30594-1 tullis 11.14.94 CH11 LP #3 } sinRemote.sin_port = pSent–>s_port; } // assign the IP address (may have to do a database lookup // if a dotted decimal IP address was not specified) sinRemote.sin_addr.s_addr = inet_addr(pszRemoteName); if (sinRemote.sin_addr.s_addr == INADDR_NONE) { pHent = gethostbyname(pszRemoteName); if (pHent == NULL) { m_nLastError = WSAGetLastError(); nStatus = CWINSOCK_WINSOCK_ERROR; break; } sinRemote.sin_addr.s_addr = *(u_long *)pHent–>h_addr; } // call the version of Write() that takes an // Internet address structure return Write(nLen, pData, &sinRemote); } return nStatus; } The third implementation of Write() takes a pointer to an Internet address structure representing the data’s destination. This is the function that does the actual work of adding the data to the write queue. After the data, its length, and the destination ad- dress are added to the write queue, a message is posted to the datagram object to trigger the sending of the data. This message is normally sent by the WinSock subsystem when- ever it’s safe to send data out the socket. But when the last message arrived from the WinSock subsystem, there might not have been any data in the write queue that was waiting to be sent. Faking the WinSock FD_WRITE event causes the socket to check the write queue and send the first piece of data waiting to be sent. ///////////////////////////////////////////////////////////////////////////// // CDatagramSocket::Write() // // Write data to the socket specified by the Internet address. // // This version of the Write() function takes an integer // representing the length of the data to send, a pointer // to the data to send, and a pointer to an Internet address // structure to send the data to. // // The data pointed to by pData must remain valid until either // the Write() function returns with an error, or the // write’s completion is notified by the m_uMsg being sent // to the window that owns this datagram object with wParam set // to CWINSOCK_DONE_WRITING or CWINSOCK_ERROR_WRITING. // int CDatagramSocket::Write(int nLen, LPVOID pData, LPSOCKADDR_IN psinRemote) p2v6 Prog. WinSock #30594-1 tullis 11.14.94 CH11 LP #3 Part III ■ WinSock Class Library 214 { int nStatus = CWINSOCK_NOERROR; while (1) { // dynamically allocate a structure to hold the // data pointer, the data’s length, and the destination address LPDATAGRAMDATA pDatagramData = new DATAGRAMDATA; if (pDatagramData == NULL) { nStatus = CWINSOCK_WINDOWS_ERROR; break; } pDatagramData–>pData = pData; pDatagramData–>nLen = nLen; memcpy(&(pDatagramData–>sin), psinRemote, sizeof(SOCKADDR_IN)); // add the data to the list TRY { m_listWrite.AddTail(pDatagramData); } CATCH (CMemoryException, e) { nStatus = CWINSOCK_WINDOWS_ERROR; break; } END_CATCH // trigger the FD_WRITE handler to try to send PostMessage(CWINSOCK_EVENT_NOTIFICATION, m_s, WSAMAKESELECTREPLY(FD_WRITE, 0)); break; } return nStatus; } CDatagramSocket::Read() The Read() member function retrieves data that was sent to the socket. The application may call Read() when the window that owns the datagram socket receives the m_uMsg message with wParam set to CWINSOCK_DONE_READING. When this message is received by the application window, lParam is the number of Read() function calls that can be ex- ecuted (that is, lParam is the number of datagram packets presently stored in the read queue). The Read() function takes a pointer to an integer (pnLen) and, optionally, a pointer to a SOCKADDR_IN structure (psinRemote). Upon successful completion of Read(), a pointer to the data is returned and the integer pointed to by pnLen contains the num- ber of bytes in the datagram returned. If a pointer was supplied for the psinRemote pa- rameter, the address of the sender of the data is returned. On error, NULL is returned. ///////////////////////////////////////////////////////////////////////////// // CDatagramSocket::Read() [...]... class that handles stream socket communications Chapters 14 and 15 use the CDatagramSocket object in complete programs p2v6 Prog WinSock #30594-1 tullis 11.14.94 CH11 LP #3 Chapter 12 s CStreamSocket 22 5 12 CStreamSocket CStreamSocket p2v6 Prog WinSock #30594-1 tullis 11.14.94 CH 12 LP #3 22 6 Part III s WinSock Class Library This chapter discusses the CStreamSocket class This class simplifies an application’s... m_pdg–>DestroySocket(); p2v6 Prog WinSock #30594-1 tullis 11.14.94 CH11 LP #3 22 3 22 4 Part III s WinSock Class Library Summary This chapter describes a class to manipulate a datagram socket The goal of this object is to enable the rapid development of a networked application using datagram communication The next chapter describes a class that handles stream socket communications Chapters 14 and 15 use the CDatagramSocket... INVALID_SOCKET; p2v6 Prog WinSock #30594-1 tullis 11.14.94 CH 12 LP #3 22 7 22 8 Part III s WinSock Class Library memset(&m_sinLocal, 0, sizeof(SOCKADDR_IN)); memset(&m_sinRemote, 0, sizeof(SOCKADDR_IN)); m_bServer = FALSE; } CStreamSocket::CreateSocket() The CreateSocket() member function creates a hidden window that’s used for WinSock messages (that is, FD_READ, FD_WRITE, FD_ACCEPT, FD_CONNECT, and FD_CLOSE)... } p2v6 Prog WinSock #30594-1 tullis 11.14.94 CH 12 LP #3 23 1 23 2 Part III s WinSock Class Library The second implementation of Connect() takes a string containing the dotted-decimal IP address of the destination or the destination host name, and a string containing either a port number or service name This version of Connect() converts the two strings into a SOCKADDR_IN Internet address structure and. .. this FD_WRITE handler if (!m_listWrite.IsEmpty()) PostMessage(CWINSOCK_EVENT_NOTIFICATION, m_s, p2v6 Prog WinSock #30594-1 tullis 11.14.94 CH11 LP #3 21 9 22 0 Part III s WinSock Class Library WSAMAKESELECTREPLY(FD_WRITE, 0)); break; } return 0L; } CDatagramSocket::DestroySocket() The DestroySocket() member function removes any data queued up on the read or write queues, closes the socket, and destroys... template for your datagram socket object message handler: LONG CMainFrame::OnWinSockEvent(WPARAM wParam, LPARAM lParam) { LPVOID pDataWritten; LPVOID pDataRead; int nLen; p2v6 Prog WinSock #30594-1 tullis 11.14.94 CH11 LP #3 22 1 22 2 Part III s WinSock Class Library SOCKADDR_IN sin; switch (wParam) { case CWINSOCK_DONE_WRITING: // lParam = pointer to data that was sent pDataWritten = (LPVOID)lParam;... OnWinSockEvent() follows It simply checks for errors and, if there are none, calls an appropriate message handler ///////////////////////////////////////////////////////////////////////////// // CDatagramSocket::OnWinSockEvent() // // Called when there is an asynchronous event on the socket // p2v6 Prog WinSock #30594-1 tullis 11.14.94 CH11 LP #3 21 5 21 6 Part III s WinSock Class Library LONG CDatagramSocket::OnWinSockEvent(WPARAM... must be specified if (nLocalPort . CDatagramSocket 20 5 p2v6 Prog. WinSock #30594-1 tullis 11.14.94 CH11 LP #3 11 11 CDatagramSocket CDatagramSocket p2v6 Prog. WinSock #30594-1 tullis 11.14.94 CH11 LP #3 Part III ■ WinSock Class Library 20 6 This. pszRemoteName, int nRemotePort) p2v6 Prog. WinSock #30594-1 tullis 11.14.94 CH11 LP #3 Part III ■ WinSock Class Library 21 2 { // convert the port number into a string and // call the version of. wParam set to CWINSOCK_ERROR_READING. // LONG CDatagramSocket::HandleRead(WPARAM wParam, LPARAM lParam) Chapter 11 ■ CDatagramSocket 21 7 p2v6 Prog. WinSock #30594-1 tullis 11.14.94 CH11 LP #3 { while

Ngày đăng: 13/08/2014, 22:21

Từ khóa liên quan

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan