DirectShow practice selection (pattern) Lu Qi
Chapter 3 Network Application 3.1 Network Programming Basic Multimedia Technology and Network Technology Combination makes online life colorful. Since then, online life is very charming; the network has changed and changing people's original lifestyle. Aunt, DirectShow is a stand-alone multimedia technology. Once the network technology is blended, DirectShow has a powerful vitality. This chapter will focus on the application of DirectShow technology in terms of network. Network programming, of course, uses Windows Socket technology. Socket-related operations are done by a series of API functions such as Socket, Bind, Listen, Connect, Accept, Send, Sendto, RECV, Recvfrom, and more. Calling these API functions have a certain order, and some of the parameters of some functions are more complicated. For developers, it is not very easy to use. Thus, Microsoft's MFC provides two classes: CasyncSocket and CSocket, which greatly facilitates the use of the socket function. The inheritance relationship between these two classes is shown in Figure 3.1. Figure 3.1 Inheritance Relationship of the MFC Socket class encapsulates the Windows Socket API at a lower level, and implements an asynchronous mechanism for Windows applications (Windows Socket APIs working in blocked by default by built) Mode, it is inconvenient to use directly on the message-driven Windows program). The CSocket class is derived from the CasyncSocket class to further simplify the application of the socket function. But unfortunately, it is because these two classes built a window, they are not thread-safe; if they want to apply the Socket feature in a multi-threaded environment, it is recommended to encapsulate the Socket API function. There are two ways to use Socket Transfer Data: TCP Transfer and UDP Transport. (The OSI Reference Model divides network communication into 7 levels, from low to the physical layer, data link layer, network layer, transport layer, session layer, representation layer, application layer; TCP and UDP are the protocol of the transport layer. Below, the two data transmission methods are introduced below.
Tip: This chapter will use two groups of keywords: Server-client and local ends. Among them, the server-client is defined according to the role; while the local end - the remote end is a relatively concept, depending on the reference, different roles can be indicated separately. For example, the server is a reference, it may be called the server for the local end, and the client is a remote end; if the client is a reference, the client is a local end, called the server as a remote end.
3.1.1 TCP Transfer TCP, Transfer Control Protocol Abbreviation (Transfer Control Protocol) is a connection-oriented network transport protocol. The TCP protocol is characterized by supporting multi-data flow operations, providing flow control and error control, and even reordering the reach of the interrogation message. Therefore, TCP provides a reliable application data transmission service. The general process reference of both communication between TCP transmission is shown in Figure 3.2. Figure 3.2 General Process of TCP Communication This section will implement a TCP transmission demonstration TCPDemo, which includes two parts of the server and client. Their program interface is shown in Figure 3.3. Figure 3.3 TCP Transfer Demonstration Program Interface TCPDemo's demo procedure is as follows: (1) Running the server and client two programs (at this point, the server has launched the sub-thread of the client connection request, the listening port number is 10028 ). (2) Enter the IP address of the server on the client program interface (if the server and client run on the same machine, the IP address can be specified as 127.0.0.1), the listening port number (because the server listens on the 10028 port Here, it should also be specified as 10028). (3) Click the "Connect" button on the client program interface to send a Socket connection request to the server. (4) The server listens to the client's connection request to accept it (so a reliable socket connection is established between the two programs). The server then sends two string data to the client. (5) After the client receives the data, pop up the message box as shown in Figure 3.4. Figure 3.4 TCP Transmission Client Receives the message box prompt displayed after the data: why is TCPDEMO to use 10028 port number as TCP communication? Because of the TCP header structure of the TCP packet, a 16-bit domain is used to represent a port number. Therefore, there are 65536 possible port numbers. However, 0-1023 is a well-known port, such as 80 is the port of Hypertext Transport Protocol HTTP, 25 is the port of the simple mail transmission protocol SMTP, 20 and 21 are port transport protocol FTP ports, etc.), more than 1023 The port number is often referred to as a high-port slogan. Applications generally provide their own communication services using high-port slogans. TCPDemo is accidentally used by 10028 ports, as long as it is larger than 1023.
TCPDemo Designed a CTCPListener class specifically for the server to listen to a specific TCP port. In addition, a CSTREAMSocket class is designed for transmission of TCP data. CStreamSocket acts as a base class, the server program derives another class CSocket Shender for data transmission, and the client program derives the CSocketReceiver class for data reception. The inheritance structure of these classes is shown in Figure 3.5. Figure 3.5 TCPDEMO class inheritance structure
Tip: About the functional introduction of both CMSGStation and CMSGReceiver, readers should be refer to the "2.4.1 a nice design pattern" of this book.
//// CTCPListener.h // #ifndef __H_CTCPListener __ # define __H_CTCPListener__ #include "CMsgStation.h" class CTCPListener: public CMsgStation {protected: SOCKET mListener; // SocketSOCKET mAccepted for listening; // with remote terminal Establish a connected socketword mlistenport; // listen for the port number BOOL MISLISTENING; / / Whether it is listening to the tag handle mlsnthread; // Listening thread public: ctcplistener (); virtual ~ ctcplistener (); public: // Setting / get Listened port number void setListenport; Word getListenPort (void); // Create / destroy socketBool create (void); void deleteListener (void); // Destroy the server to establish a connection with the client SocketVoid deleteAccepted (void); // Start / stop the listening thread Bool StartListening (Void); Void stoplistence (void); // Get the server and the client to establish a connection to the connected socket (for data transfer) socket getaccepted (void); private; : BOOL Accept (Void); // Accept the remote end connection request static dword WinApi Listeningthrd (void * pParam); // Listen thread executive}; #ENDIF / / __H_CTCPLISTENER__ // // ctcplistener.cpp // # include " STDAFX.H "#include" ctcplistener.h "#include" netdefs.h "#ifdef _debug # define new debug_new # undef this_filestatic char this_file [] = __file __; # Endif // ctcplistener :: ctcplistener () {// Initialize mListener = INVALID_SOCKET; mAccepted = INVALID_SOCKET; // default listening on port 10028 mListenPort = 10028; mLsnThread = NULL; mIsListening = FALSE;} CTCPListener :: ~ CTCPListener () {// destruction SocketDeleteAccepted (); DeleteListener (); // Stop listening thread stoplistence ();} // Sets the listening port number void ctcplistener :: setListenport (Word Inport) {mlistenport = inport;} // get the listening port number word ctcplistener :: getListenport Void) {Return Mlistenport;} // Create SocketBool Ctcplistener :: Create (Void) {DeleteListener (); // Destroy Socket Int Val = 0; BOOL Pass = false; // Create a TCP Transfer SocketMlistener = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); if (mlistener! = Invalid_socket) {// During the Socket, the parameter setting box is set;
Setsockopt (mlistener, ipproto_tcp, tcp_nodelay, (char *) & Sopt, sizeof (bool)); // Don't wait until you destroy the Socket, you don't have to send out SetSockopt (Mlistener, SOL_Socket, SO_DONTLINGER, (CHAR *) & Sopt, SIZEOF (BOOL)); // Bind Socket to the specified listening port sockaddr_in addr; memory (& addr, 0, sizeof (sockaddr_in)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = HTONL (INADDR_Any); addr .sin_port = htons (mlistenport); val = bind (mlistener, (strunt socketdr *) & addr, sizeof (addr)); pass = (val! = socket_error);} if (pass) {// Place Socket in listening State Val = listen (mlistener, somaxconn); pass = (val! = Socket_error);} if (! Pass) {deleteListener ();} return pass;} // destroyed Socketvoid Ctcplistener :: DeleteListener (Void) ) {if (mListener = INVALID_SOCKET) {closesocket (mListener);! mListener = INVALID_SOCKET;}}! // server and client establishes destruction Socketvoid CTCPListener connection :: DeleteAccepted (void) {if (mAccepted = INVALID_SOCKET) {closesocket ( Maccepted = invalid_socket;}} // Start the listening thread (blocked when it is used to accept the Accept function call to accept the connection request) BOOL CTCPListener :: StartLisTening (void) {// If the listening socket is not created, then create IF (mlistener == invalid_so CKET) {create ();} if (mlistener! = Invalid_socket) {if (mislistening) {return true;} // launching the listening thread dword threadID = 0; mlsnthread = CreateThread (Null, 0, ListeningThrd, this, 0, 0, & threadID); return (mLsnThread = NULL);!} return FALSE;} // stop listening thread void CTCPListener :: StopListening (void) {if (mListener = INVALID_SOCKET && mIsListening) {// destruction listener Socket, then Accept! The separation of the blocked state deleteListener (); // Waiting for the detection thread completely exits if (mlsnthread! = Null) {WaitForsingleObject (mlsNThread, Infinite); mlsnthread = null;}}} // Accept remote end connection request (create a new) Socket is used to establish a connection with the remote side) Bool CTCPListener :: Accept (void) {if (mlistener! = Invalid_socket) {sockaddr_in saddr;
INT LEN = SIZEOF (SOCKADDR_IN); // Listening to the remote side connection request (if there is no connection request, this function will block) socket accountd = accept (mlistener, (sockaddr *) & saddr, & len; if (acid); if (acid) {RETURN FALSE;} // Note: Currently only supporting an Socket connection! / / Open the previous connection to DELETEACCEPTED (); // to save the previous connection to establish a connection with the remote side to establish a connection; // Set some parameters on the Socket Bool Sopt = true; setsockopt (Maccepted, Ipproto_TCP, TCP_Nodelay, (Char *) & Sopt, SizeOf (Bool)); Setsockopt (Maccepted, SOL_Socket, SO_DONTLINGER, (CHAR *) & Sopt, SizeOf (Bool)); Return true;} Return False;} // When connected to the remote side After the Socket is removed, save the Socket variable is set to invalid // Removed Socket is responsible for destroying socket ctcplistener :: getAccepted (void) {socket return = maccept; maccepted = invalid_socket; return return;} // Listen thread executable function DWORD WINAPI CTCPListener :: ListeningThrd (void * pParam) {ASSERT (pParam); // The listener object pointer CTCPListener * pListen = (CTCPListener *) pParam; pListen-> mIsListening = TRUE; while (pListen-> mIsListening ) {// Start listening (if there is no remote end to send a connection request, this function will block) if (! PListen-> Accept ()) {plis-> mislistening = false; Break;} else {// constling cnewsocketaccepted = 6688; // Send a custom message for the upper layer CNEWSocketAccepted, // indicates a Socket connection has been established (you can use it to transmit data!) PListen-> Broadcast (CNewsocketAccepted;}} Return 1;} /// / Cstreamsocket.h // #ifndef __h_cstreamsocket __ # define __h_cstreamsocket__ class cs TreamSocket {protected; // for data transmission or reception socketBool missnected; // socket has established a connection BOOL MISRECEIVING; // Use a stand-alone thread to receive the data to receive Handle MRCVThread; Bool Missending; // Independent threads perform data to send handle msndthread; public: cstract (); virtual ~ cstract (Socket Insocket); // Associated a socketvoid Detach (Void);
// Destroy socket // Send a connection to the specified IP address, the port number machine to send a connection request BOOL ConnectTTTTTTTTTTTTTTTTTTT; BOOL ISCONNECTED {Return Misconnected;}; // Used for data reception control functions BOOL StartReceiving (void); void StopReceiving (void); BOOL IsReceiving (void) {return mIsReceiving;}; // data for controlling the function BOOL StartSending (void) transmitted; void StopSending (void); BOOL IsSending (void) { Return missending;}; protected: static dword WinAPI ReceIvingthrd (Void * PPARAM); // Receive Thread Optics Static DWORD WINAPI SENDINGTHRD (VOID * PPARAM); // Send Thread Optics // Receive / Send Data Cycling Process (virtual function for custom subclass) virtual void ReceivingLoop (void); virtual void SendingLoop (void);}; #endif // __H_CStreamSocket__ // // CStreamSocket.cpp // #include "stdafx.h" #include "CStreamSocket.h" #include "UNetwork.h" #ifdef _DEBUG # define new DEBUG_NEW # undef THIS_FILEstatic char THIS_FILE [] = __FILE __; # endif // CStreamSocket :: CStreamSocket () {// initialize mSocket = INVALID_SOCKET; mIsConnected = FALSE; mIsReceiving = FALSE MISSENDING = false; mrcvthread = null; msndthread = null;} // destroy Socket, stop sending / receiving thread cstractReamSocket :: ~ cStreamsock Et () {Detach (); stopsending (); stopRecEnding ();} // Associated a socket to this Packaging Object Bool CStreamSocket :: attach (socket inSocket) {// If you have already wrapped a socket, return an error value if (mSocket = INVALID_SOCKET!) {return FALSE;} // save Socket handle mSocket = inSocket; mIsConnected = TRUE; return TRUE;} // destruction Socketvoid CStreamSocket :: Detach (void) {if (mSocket = INVALID_SOCKET!) {closesocket (mSocket); mSocket = INVALID_SOCKET; mIsConnected = FALSE;}} // machine sends the specified IP address, the port number of the connection request BOOL CStreamSocket :: ConnectTo (const char * inTarget, WORD inPort) {if (mIsConnected) {return TRUE ;} // First create a TCP transmission socketMsocket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); if (msocket! =
INVALID_SOCKET) {// adjustable in Socket successfully created parameter BOOL sopt = TRUE; setsockopt (mSocket, IPPROTO_TCP, TCP_NODELAY, (char *) & sopt, sizeof (BOOL)); setsockopt (mSocket, SOL_SOCKET, SO_DONTLINGER, (char *) & sopt, sizeof (BOOL)); // send a connection request to the server SOCKADDR_IN saddr; memset (& saddr, 0, sizeof (SOCKADDR_IN)); saddr.sin_addr.S_un.S_addr = inet_addr (inTarget); saddr.sin_family = AF_INET; saddr .SIN_PORT = HTONS ((Word) Inport); if (Connect, Msocket, SockAddr *) & Saddr, Sizeof (SockAddr_in))! = 0) {// Track Socket Error #ifDef _DebuguNETWork :: DumpsocketError (); # ENDIF / / If the connection fails, destroy the socketdetach (); return false;} misconnected = true; returnne;}} // Start data receiving thread (blocked when the socket data reception function is called) BOOL CSTREAMSOCKET: : StartReceiving (void) {if (! mSocket = INVALID_SOCKET) {if (mIsReceiving) {return TRUE;} DWORD threadID = 0; mRcvThread = CreateThread (NULL, 0, ReceivingThrd, this, 0, & threadID); return (mRcvThread =! NULL);} Return False;} // Stop Data Receive Thread VOID CSTREAMSOCKET :: StopeVing (Void) {if (MISRECEIVING) {// Destroy Socket, make the reception function fail to block DETACH (); // Wait for data receiving thread Fully exit IF ( ! MRcvThread = NULL) {WaitForSingleObject (mRcvThread, INFINITE); mRcvThread = NULL;}!}} // the data transmission thread (to increase data transmission efficiency) BOOL CStreamSocket :: StartSending (void) {if (mSocket = INVALID_SOCKET) {if (missending) {return true;} dword threadid = 0; msndthread = Createthread (Null, 0, Sendingthrd, this, 0, & threadid); return (MsndThread! = null);} Return False;} // Stop Data Send Thread Void CStreamSocket :: StopSending (Void) {if (missending) {// Destroy socket, make the send function fails or detached from blocking Detach (); if (msndthread! = Null) {// Waiting for the data to send thread complete exit WaitForsingleObject ( Msndthread, Infinite; msndthread = null;
}}} // executable function data receiving threads DWORD WINAPI CStreamSocket :: ReceivingThrd (void * pParam) {CStreamSocket * pSock = (CStreamSocket *) pParam; if (pSock) {pSock-> mIsReceiving = TRUE; // perform reception cycle pSock-> ReceivingLoop (); return 1;} return 0;} // executable function data transmission threads DWORD WINAPI CStreamSocket :: SendingThrd (void * pParam) {CStreamSocket * pSock = (CStreamSocket *) pParam; if (pSock ) {psock-> missending = true; // Perform send cycle psock-> sendingLoop (); return 1;} return 0;} // virtual function,} subsidy custom actual data reception (loop) process void cstreamsocket :: ReceivingLoop (void) {} // virtual function for custom subclass actual data transmission (cycle) the process void CStreamSocket :: SendingLoop (void) {} //// CSocketSender.h // #ifndef __H_CSocketSender __ # define __H_CSocketSender__ #include "CStreamSocket.h" class CSocketSender: public CStreamSocket {public: CSocketSender (); virtual ~ CSocketSender (); protected: virtual void SendingLoop (void); // process the customization data transmission}; #endif // __H_CSocketSender__ //// CSocketSender .cpp //// server program customized data Send Procedure VOID CSOCKETSENDER :: SendingLoop (void) {charf [1024]; // Send data Used Cache INTES = 0; // Defines a string as a transmitted data CHAR STR [] = "HQ Tech, MAK e technology Easy! "; // Send data total length = string length header information length int LEN = strs sizeof (net_header); // Plus a custom header information before the data content (for Description of the length of the data content) NET_HEADER * PHEADER = (Net_Header *) BUF; PHEADER-> PACK_SIZE = Strlen (STR); Pheter-> my_hton (); // byte sequential conversion! // The data content and header information that will be sent will integrate strcpy (buf sizeof (net_header), str); / / as a demonstration, send the above-described string data twice int COUNTER = 2; while (missending) {/ / Using Socket to send Bytes = Send (Msocket, BUF, LEN, 0); if (bytes == Socket_ERROR) {Detach (); missending = false; break;} // After completing twice, disconnect SOCKET Connection, end the transmission thread IF (--counter == 0) {DETACH (); missending = false; Break;
}}} //// CSocketReceiver.h // #ifndef __H_CSocketReceiver __ # define __H_CSocketReceiver__ #include "CStreamSocket.h" class CSocketReceiver: public CStreamSocket {public: CSocketReceiver (); virtual ~ CSocketReceiver (); protected: virtual void ReceivingLoop (void ); // custom data receiving process}; #ENDIF / / __H_CSOCKETRECEIVER__ / / / CSOCKETRECEIVER.CPP //// Client Program Customized Data Receive Procedure VOID CSOCKETRECEIVER :: ReceivingLoop (Void) {// Receive Data Used Cache CHAR BUF [1024]; INT_HETES = 0; net_header * pHeader = (net_header *) BUF; While (MISRECEIVING) {// First receives a header information (including subsequent valid data length in the header information) BYtes = Recv (MSocket , BUF, SIZEOF (NET_HEADER), 0); if (bytes == Socket_ERROR || BYTES == 0) {DETACH (); MISRECEIVING = false; Break;} PHEADER-> my_ntoh (); // byte sequential conversion! / / Continue to read subsequent valid data (ie a string content) BYTES = Recv (Msocket, BUF, PHEADER-> PACK_SIZE, 0); if (bytes == Socket_ERROR || Bytes == 0) {DETACH (); MISRECEIVING = false; Break;} buf [Bytes] = '/ 0'; // Pop up a message box Display the received string content cstring msg = "received content: / n"; afxMessageBox (MSG BUF);}} So how come TCPDemo to use CTCPListener, CSTREAMSOCKET, CSOCKETSENDER, CSOCKETRECEIVER? Let's take a look at the server program TCPServer. This is a dialog-based MFC program. It defines two members in the dialog class CTCPServerDLG: one is an instance of the CTCPListener class, one is an instance of the CSocket Shender class. The former is used to listen to the client's connection request, the latter being responsible for the actual Socket data transmission. Then, create the Socket used to listen in the initialization function of the main dialog and start the listening thread. When a client issues a connection request, and after the server is successfully accepted, the data transmission thread is started to actually start the data.
// TCPServerDlg.h: header file // class CTCPServerDlg: public CDialog, public CMsgReceiver {public: CTCPServerDlg (CWnd * pParent = NULL); protected: HICON m_hIcon; CTCPListener mListener; // client listening for connection requests CSocketSender MNetSender; // Data Send // Custom Message Process Virtual Bool ReceiveMessage (Messaget Inmessage, Void * Ioparam, Void * Ioparam2); // Other Member Definition (omitted) // ...}; // TCPServerdlg. cpp: implementation file // CTCPServerDlg :: CTCPServerDlg (CWnd * pParent / * = NULL * /): CDialog (CTCPServerDlg :: IDD, pParent) {// {{AFX_DATA_INIT (CTCPServerDlg) mHostPort = 10028; //}} AFX_DATA_INIT / / Note that LoadIcon does not require a subsequent DestroyIcon in Win32m_hIcon = AfxGetApp () -> LoadIcon (IDR_MAINFRAME);} // initialization function BOOL main dialog CTCPServerDlg :: OnInitDialog () {CDialog :: OnInitDialog (); // Set The icon for this dialog. The framework does this Automatic or //hen the application's main window is not a dialogseticon (m_hicon, true); // set big iconseticon (m_hicon, false); // set small icon // Get local machine IP address, machine name, and show char hostname on the interface [100]; Char Hos TIP [50]; if (Unergy) {MedithostName.SetWindowText (HostName); MedithostP.SetWindowText (Hostip);} // The main interface is an observer of mlistener object (because it wants to get Socket Notice of Connection) Mlistener.addmsgreceiver (this); // Sets the listener port number mlistener.setListenport (MHOSTPORT); // Create a listening socket, start a listening thread IF after successful (mlistener.create ()) {mlistener .StartListening ();} return true; // Return True unless} // When receiving the Socket connection has been established, the startup data transmission thread will send data BOOL CTCPSERVERDLG :: ReceiveMessage ( MessageT inMessage, void * ioParam, void * ioParam2) {if (inMessage == cNewSocketAccepted) {// Get establishing SocketmNetSender.Attach (mListener.GetAccepted connection ()); // the data transmission thread mNetSender.StartSending (); return True;
} Return CMSGRecEver :: ReceiveMessage (IonMessage, IOPARAM2);} Tip: When using the MFC to develop a Socket program, you typically include an AFXSock.h header file (you can add in the stdafx.h file). Before running, call the AFXSocketinit function to initialize the Socket function library, as follows:
/// TCPServer.cpp :: InitInstance () {// --- The initialization of the Socket Function library --- // AFXSocketinit Internal calling the wsastartup function, // and can guarantee WSACleanup automatically before the program exits function! IF (AFXSocketinit ()) {AFXMessageBox ("Socket Initializing Failded!"); Return False;}
// Create a main dialog box CTCPServerDLG DLG; m_pmainwnd = & dlg; int nresponse = DLG.Domodal (); if (nresponse == idok) {} else if (nresponse == idcancel) {} returnaf
Let's see the implementation of the client program TcpClient. This is also a dialog-based MFC program. It defines an instance of a CSocketReceiver class in a dialog class CTCPClientDLG that is specifically used to issue a connection request to the server, and the data transmitted by the server. // TCPClientDlg.h: header file // class CTCPClientDlg: public CDialog {public: CTCPClientDlg (CWnd * pParent = NULL); protected: HICON m_hIcon; CSocketReceiver mNetReceiver; // // other member for receiving the data definitions (not) / / ......}; // TCPClientDlg.cpp: implementation file // CTCPClientDlg :: CTCPClientDlg (CWnd * pParent / * = NULL * /): CDialog (CTCPClientDlg :: IDD, pParent) {// {{AFX_DATA_INIT (CTCPClientDlg) mTargetIP = _T ("127.0.0.1"); mtargetport = 10028; //}} AFX_DATA_INIT // Note That LoadICon Does Not Require A Subsequent Destroyicon In Win32M_HICON = AFXGetApp () -> loadicon (iDR_mainframe);} // main dialog initialization function BOOL CTCPClientDlg :: OnInitDialog () {CDialog :: OnInitDialog (); // Set the icon for this dialog The framework does this automatically // when the application's main window is not a dialogSetIcon (m_hIcon, TRUE);. // Set big iconseticon (m_hicon, false); // SET SMALL ICON / / Get the IP address of the local machine, the machine name, and display char hostname on the interface; char hostip [50]; if (UnetWork :: gethostinfo) Hostip, hostname) {MedithostName.SetWindowText (HostName); Medithostip.SetWindowText (Host) IP);} Return True; // Return True Unlessata on the "Connect" button on the interface on the interface void ctclientdlg :: OnButtonConnect () {// Get the latest data on the interface Updatedata (TRUE); / / To the specified IP address, the server issues a connection request if (MNETRECEIVER.CONNECTTTTO (Mtarget)) {// After successful, start a sub-thread for data reception MNETRECEIVER.STARTRECEIVING ();} ELSE {// Pop-up message box cstring msg; msg.format ("Connecting TO% S:% D Failed!", mtargetip, mtargetport; AFXMESSAGEBOX (MSG);}}}} TCPSERVER and TCPCPCLIENT two programs throughout the interaction The process is shown in Figure 3.6. Figure 3.6 The interaction process of TCPServer and TCPCPClient is worth noting that TCP is transmitted a byte stream data.
In the application, sometimes some of the data is required, or some descriptions are obtained. Thus, both TCPServer and TCPClient two programs define a simple application protocol when performing TCP communication, that is, the data emitted by TCPServer always uses a "load head load data" structure. Wherein load data is the data content that truly needs to be transmitted, and the load head is a description of the load data indicating the actual length of the load data. The definition of this negative load is as follows: ///////////////////// Using an unsigned integer variable to illustrate the length // of the load data // Put the variable value of this structure, from the host word Sequential sequence conversion into network byte sequence void my_hton (void) {pack_size = htonl (package); // convert the variable value of this structure to host byte sequence from network byte sequence void my_ntoh (void) {PACK_SIZE = NTOHL (Pack_Size);};}; small knowledge: Byte order is very concerned about byte order, because it is really rarely used. What is the sequence of bytes? Let us first look at an example, suppose now there is a Word type variable, its value is 0x7788, then how is it stored in memory? Figure 3.7 Two byte sequence is actually possible for different CPUs, different operating systems, two bytes in Figure 3.7 are possible. If the left side of Fig. 3.7 is: High byte, the low byte is after, this type of byte is called a BIG-endian; if the right side of Figure 3.7: The low byte is before, the high byte is behind, This type of byte is called Little-Endian. Table 3.1 Common CPUs, byte sequential CPU operating system byte sequential X86 (Intel, AMD, etc.) All little-endiandec alpha all little-endianhp-pa NT Little-endianhp-PA unix Big-endiansun SPARC Big-endianmips NT Little-endianmips UNIX BIG-EndianPowerPC NT Little-endianpowerPC NT BIG-EndianRS / 6000 Unix Big-endianmotorola M68K All Big-Endian Generally, we don't have to care about byte order, unless it is involved in cross-platform Communication and resource sharing, such as the network programming that this chapter will introduce (Network Transmission Protocol TCP / IP is BIG-Endian). What should I do now to transfer and exchange data between machines using different bytes? (The same data, different machines may have different understandings, don't be able to have two ways, one is all converted into text to transmit, the other is that both parties are transmitted in accordance with the byte order of some side. (At this time, there is a mutual conversion problem between different byte sequences). A second method is often used in Socket programming.
The entire transmission process is as follows: The sending end converts the data of the unit into the network's byte order (call API function htonl or htons), then send; after receiving network data, first convert the data in the byte order of the machine ( Call the API function NTOHL or NTOHS), then do other operations - so able to guarantee the "conference spirit" to communicate correctly! Several API functions used in this process: NTOHL, HTONL, NTOHS, HTONS, name are almost, it is difficult to distinguish. But if you know their origins, the problem doesn't exist: n is the meaning of NetWork, the network; H is Host, the local host meaning. NTOHL, is to convert 32-bit U_LONG type data from network byte sequential order (HTONL's byte sequence conversion process is opposite to NTOHL); NTOHS, is the data of 16-bit U_Short types from network bytes Sequential conversion cost machine byte sequence (HTons's byte sequence conversion process is opposite to NTOHS). Finally there is a small problem: How do I know the byte order of this machine? There is a very simple method, as follows: bool islittlendian (void) {word wvalue = 0x5678; return (* ((Byte *) & wvalue) == 0x78);} In addition, TCPServer programs and TCPCPCLIENT programs have been used in implementation Tool class UnergyK. This class implements two static member functions: gethostinfo and dumpsocketError. The former is used to obtain the IP address, machine name, etc. of the local host, and the latter tracks the Socket error when program debugging. Especially DumpSocketError functions, very practical.
Because the debugging of the socket program is generally troublesome, then the DumpSocketError function can convert the integer Socket error code into a string of easy understanding, which is very convenient! //// Uneetwork.cpp /// Obtain the IP address of the local host and machine name Bool Uneetwork :: gethostinfo (char * out, char * outname) {char name [300]; // Get the host name IF (GethOstname Name, 300) == 0) {if (Outname) {structure;} // Get the host's IP address phostent hostinfo; if ((HostInfo = gethostbyname (name))! = null) {lpcstr pip = INET_NTOA (* (STRUCT IN_ADDR *) * HostInfo-> h_addr_list); strcpy (outip, pip); return true;}}} Return False;} // Transforms integer Socket error code into string Description Form Output Void Uneetwork: : DumpSocketError (void) {switch (WSAGetLastError ()) {case WSANOTINITIALISED: TRACE ( "A successful WSAStartup call must occur before using this function."); break; case WSAENETDOWN: TRACE ( "The network subsystem has failed."); break; case WSAEACCES: TRACE ( "The requested address is a broadcast address, but the appropriate flag was not set Call setsockopt with the SO_BROADCAST parameter to allow the use of the broadcast address.."); break; case WSAEINVAL: TRACE ( " An Unknown Flag Was Specified, or MSG_OOB WAS SPECified for a socket with so_oobinline enabled. "); Break; Case Wsaeintr: Trace (" A BL ocking Windows Sockets 1.1 call was canceled through WSACancelBlockingCall "); break; case WSAEINPROGRESS: TRACE (". A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function "); break; case WSAEFAULT.: TRACE ( "The buf or to parameters are not part of the user address space, or the tolen parameter is too small."); break; case WSAENETRESET: TRACE ( "The connection has been broken due to keep-alive activity detecting a failure While the Operation Was in Progress. "); Break; Case Wsaenobufs: Trace ("
NO Buffer Space Is Available. "); Break; Case WSAENOTCONN: Trace (" "The socket is not connection (" The descriptor is not a socket) ("The descriptor is not a socket) (" the descriptor is not a socket) ("the descriptor is not a socket).") ; break; case WSAEOPNOTSUPP: TRACE ( "MSG_OOB was specified, but the socket is not stream-style such as type SOCK_STREAM, OOB data is not supported in unidirectional and supports only receive operations the communication domain associated with this socket, or the socket is . "); break; case WSAESHUTDOWN: TRACE (" The socket has been shut down; it is not possible to sendto on a socket after shutdown has been invoked with how set to SD_SEND or SD_BOTH "); break; case WSAEWOULDBLOCK:. TRACE ( "The socket is marked as nonblocking and the requested operation would block."); break; case WSAEMSGSIZE: TRACE ( ". The socket is message oriented, and the message is larger than the maximum supported by the underlying transport"); break Case WSAEHOSTUNREACH: TRACE ("The Remote Host Cannot Be Reached from this Host At this time.") ; Break; case WSAECONNABORTED: TRACE ( "The virtual circuit was terminated due to a time-out or other failure The application should close the socket as it is no longer usable.."); Break; case WSAECONNRESET: TRACE ( "The virtual circuit was reset by the remote side executing a hard or abortive close. For UPD sockets, the remote host was unable to deliver a previously sent UDP datagram and responded with a / "Port Unreachable /" ICMP packet. The application should close the socket as IT is no luck Usable. "); Break; Case WSAEADDRNOTAVAIL: Trace (" The Remote Address is not a valid address, for example, addr_any. "); break; case wsaeafnosupport: trace ("
Addresses in the specified family can not be used with this socket "); break; case WSAEDESTADDRREQ: TRACE (". A destination address is required "); break; case WSAENETUNREACH: TRACE (". The network can not be reached from this host at this . time "); break; case WSAETIMEDOUT: TRACE (" The connection has been dropped, because of a network failure or because the system on the other end went down without notice "); break; default: TRACE (". Unknown socket error Break;}} prompt: This book provides a full implementation of the TCP Transfer Demonstration in the SourceCodes / Chapter03 / TCPDemo directory of this book. Where TCPServer is a server program, TCPClient is a client program. Open WSClientServer.dsw Browse TCPServer and TCPClient at the same time.
3.1.2 UDP Transport UDP, User DataGram Protocol Abbreviation (User Data News Agreement) is a connected network transport protocol. The UDP protocol is provided is a basic, low-delayed transmission service called a datagram. UDP transmission does not need to be established in advance as TCP transmission; UDP does not timetime mechanism, flow control or congestion management mechanism, due to some reason, is not retransmitted. Therefore, UDP provides an unreliable application data transmission service.
Tip: The main difference between TCP and UDP is reliability. But not, because UDP is an unreliable transmission protocol and is useless. In a good network environment (such as a local area network), use UDP transfer data is quite reliable, and the efficiency is relatively high. UDP (than TCP) is more suitable for transmission of application data related to time.
This section will implement a UDP-transmitted demo UDPDEMO, which includes two parts: servers and clients. Their program interface is shown in Figure 3.8. Figure 3.8 UDP Transfer Demo Interface UdpDemo's demo procedure is as follows: (1) Running the server and client two-part programs (at which time the server launches sub-threads for receiving 10025 port data, and the client also started A sub-thread that receives 10026 port data). (2) Enter the IP address of the server on the client program interface (if the server and client run on the same machine, the IP address can be specified as 127.0.0.1), the port number received by the data (because the server is received on the 10025 port) Data, here should also be specified as 10025). (3) Editing the contents of the message on the client program interface, then click the "Send" button to issue UDP data to the server. (4) The server will pop up the message box on the left of Figure 3.9 after receiving the data sent by the client. Subsequently, the server sends a feedback message to the client. (5) The client receives a message box after receiving the feedback data sent by the server, as shown in Figure 3.9. Figure 3.9 A pair of message boxes displayed during the UDP transmission UDPDemo designed a CudpManager class to be responsible for the sending and reception of UDP data (data reception using a separate sub-thread).
CUDPManager class definition and implementation of the following: //// CUDPManager.h // #ifndef __H_CUDPManager __ # define __H_CUDPManager__ class CUDPManager {private: SOCKET mSckReceiver; // for receiving SocketSOCKET mSckSender; // SocketDWORD mTargetIP for transmission; / / Remote IP address (using host byte order) Word mtargetport; // Remote port number word mlocalport; // is receiving data for tag handle mrcvthread; // data receiving thread handle public: cudpManager (); ~ CudpManager (); // Setting / get the IP address void setTargetIP (DWORD INIP); DWORD GETTARGETIP (VOID); void getTargetip (CHAR * OUTIP); // Setting / Get a remote port number void setTargetPort (Word Inport); // Setting / Get local port number void setlocalport (Word Inport); Word getLocalPort (void); // Create / destroy SocTBool Createender (void); void deletesender (void); // Create / destroy the socketBool CreateReceiver (void); void deleteReceiver; // Use the UDP protocol to send data Bool Send (const char * inbuffer, Long inLength; Bool Sendto (Const Char * Inbuffer, Long Inlength, DWORD INIP, WORD); // Start / Stop Data Receive Thread Bool StartReceiving (Void); Void StopeVing (Void); Priv ATE: Void ReceivingLoop (Void); // Data Receive Cycle Procedure Static DWORD WINAPI ReceivingThrd (Void * PParam); // Receive Thread Execution Body}; #ENDIF / / __H_CUDPMANAGER__ /// CudpManager.cpp // #include "stdafx .h "#include" CUDPManager.h "#include" UNetwork.h "#ifdef _DEBUG # define new DEBUG_NEW # undef THIS_FILEstatic char THIS_FILE [] = __FILE __; # endif / CUDPManager :: CUDPManager () {// initialize mSckReceiver = INVALID_SOCKET; mSckSender = INVALID_SOCKET; mTargetIP = 0x7f000001; // 127.0.0.1mTargetPort = 10080; mLocalPort = 10080; mIsReceiving = FALSE; mRcvThread = NULL;} CUDPManager :: ~ CUDPManager () {// destroy all used SocketDeleteSender () DeleteReceiver (); stopRecEcing ();} // Set the IP address of the remote end,
The parameter is DWORD Type Void CudpManager :: SetTargetip (DWORD INIP) {mtargetip = inip;} // Get the IP address of the remote end DWORD CUDPMANAGER :: GetTargetip (void) {Return Mtargetip;} // Restart function: Set the IP address of the remote end The parameter is a string type void cudpmanager :: setTargetip (const char * inIP) {// convert the IP address from the string into DWORD type (using host byte order) mtargetip = ntohl (inet_addr (inIP));} / / Overload function: Get a string of the remote end Void CudpManager :: getTargetip (char * outip) {if (outip) {// convert the IP address from the DWORD type into string form Struct in_addr in; in (UN) .S_addr = htonl (mtargetip); char * pstr = inet_ntoa (in); strcpy (outip, pstr);}} // Set remote port number void cudpManager :: setTargetPort (Word Inport) {mtargetport = inport;} // get remote port number WORD CUDPManager :: GetTargetPort (void) {return mTargetPort;} // set the local port number void CUDPManager :: setLocalPort (WORD inPort) {mLocalPort = inPort;} // get the local port number WORD CUDPManager :: getLocalPort (void ) {return mLocalPort;} // Create SocketBOOL CUDPManager :: CreateSender (void) {DeleteSender for transmission (); // Create a UDP transport SocketmSckSender = socket (AF_INET, SOCK_DGRAM, 0);! if (mSckSender = INVALID_SOCKET ) {RETURN TRUE;} // Destroy Socketvoid CudpManager for sending: : DeleteSender (void) {if (! MSckSender = INVALID_SOCKET) {closesocket (mSckSender); mSckSender = INVALID_SOCKET;}} // Create a SocketBOOL CUDPManager reception :: CreateReceiver (void) {DeleteReceiver (); // Create a UDP transmission SocketmSckReceiver = socket (AF_INET, SOCK_DGRAM, 0); if (! mSckReceiver = INVALID_SOCKET) {// Socket is provided on the parameters: allow address multiplexing BOOL flag = TRUE; int ret = setsockopt (mSckReceiver, SOL_SOCKET, SO_REUSEADDR, ( Char *) & flag, sizeof (flag)); if (RET == Socket_ERROR) {deleteReceiver (); return false;} // Bind Socket to local port number SockAddr_in addr; addr.sin_family = AF_INET; addr.sin_addr .s_addr = htonl (inaddr_any); addr.sin_port = htons (mlocalport); RET =
bind (mSckReceiver, (struct sockaddr *) & addr, sizeof (addr)); if (ret == SOCKET_ERROR) {DeleteReceiver (); return FALSE;} return TRUE;} return FALSE;} // for receiving destruction Socketvoid CUDPManager :: DeleteReceiver (void) {if (mSckReceiver = INVALID_SOCKET!) {closesocket (mSckReceiver); mSckReceiver = INVALID_SOCKET;}} // have been created using well Socket for transmitting transmission data BOOL CUDPManager :: send (const char * inBuffer , long inLength) {SOCKADDR_IN addr; memset ((char *) & addr, 0, sizeof (addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl (mTargetIP); addr.sin_port = htons (mTargetPort); // Use Socket to send data INT VAL = Sendto (Mscksender, Inbuffer, INLENGTH, 0, (SockAddr *) & addr, sizeof (limited);} // Create a new Socket, and use it Send data to the specified IP address, port number Bool CudpManager :: Sendto (Const Char * Inbuffer, Long Inlength, DWORD INIP, WORD INPORT) {// Create a UDP Transfer Socket Sock = Socket (AF_INET, SOCK_DGRAM, 0 ); if (sock! = invalid_socket) {sockaddr_in addr; memset ((char *) & addr, 0, sizeof (addr)); addr.sin_family = Af_Inet; addr.sin_addr.s_addr = HTONL (i NIP); addr.sin_port = htons (inport); // Send Data INT VAL = Sendto (Sock, Inbuffer, INLENGTH, 0, (SockAddr *) & addr, sizeof (addr)); if (val == Socket_ERROR) {/ / Tracking socket error #ifDef _debugunet :: DUMPSOCKETEETWORK :: DUMPSOCKETEETWORK :: DUMPSOCKETERROR (); Return (Val! = Socket_ERROR);} Return False;} // Start data receiving thread (because of call recvfrom function block when receiving UDP data) BOOL CUDPManager :: StartReceiving (void) {if (mSckReceiver == INVALID_SOCKET) {createReceiver ();} if (mSckReceiver = INVALID_SOCKET) {if (mIsReceiving) {return TRUE;!} DWORD threadID = 0; mrcvthread = CreateThread (Null, 0, Receivingthrd, this, 0, & threadid); return (mrcvthread! = Null);
} Return False;} // Stop Data Receive Thread VOID CUDPMANAGER :: StopReceiving (Void) {if (MISRECEIVING) {// Destroy Socket to make the reception function fail to block DeleteReceiver (); // Wait for the receiving thread completely exit IF ( ! mRcvThread = NULL) {WaitForSingleObject (mRcvThread, INFINITE); mRcvThread = NULL;}}} // executable thread function: a function call of this class ReceivingLoop DWORD WINAPI CUDPManager :: ReceivingThrd (void * pParam) {ASSERT (pParam); CUDPManager * pController = (CUDPManager *) pParam; pController-> ReceivingLoop (); return 0;} // data receiving process void CUDPManager :: ReceivingLoop (void) {struct sockaddr_in addr_cli; int addr_cli_len = sizeof (addr_cli); char buffer [ 1024]; // Send data cache long Bytes = 0; MISRECEIVING = true; while (MISRECEIVING) {// Wait for reception data int Addr_cli_len = sizeof (addr_cli); bytes = recvfrom (MsckRecEver, (char *) Buffer, 1024, 0 , (Lpsockaddr) & addr_cli, (int *); if (bytes == Socket_ERROR || Bytes == 0) {// If the socket sends an error or Socket disconnection, the loop MISRECEIVING = false;} else {buffer [ BYTES] = '/ 0'; // Get the IP address of the remote end Char * pstr = inet_ntoa (addr_cli.sin_addr); // Check the tag: Do you need a feedback message? / / As a demo, the first byte of the transmitted UDP packet is used to indicate whether it is necessary to feedback: // 1 indicates that it is necessary to feedback, 0 means no feedback IF (buffer [0] == '1') {// The remote side issues a feedback message, the first byte is specified as 0, // means no longer needs remote end feedback, otherwise the data transmission of both parties will never stop! CString str = "0Received OK."; Sendto (STR, Str.getLength () 1, NTOHL (INET_ADDR (PSTR)), 10026); // Pop up a dialog box displays the received data content cstring msg; msg. Format ("Receive FROM% S / NCONTENT:% S", PSTR, Buffer 1); AFXMessageBox (MSG);}}} Reconfers the specific implementation of server programs UDPServer and client programs UDPCLIENT. They are all MFC programs based on dialog and are defined in the respective master dialog classes. Examples of a CudpManager class. Then a series of operations in the initialization function of the dialog, including the Socket for creating UDP transmission, starting data receiving threads, etc.
// udpserverdlg.h: header file // class cudpserverdlg: public cdialog {protected: cdial mudpManager; // Other member definition (omitted) // ...}; // udpserverdlg.cpp: Implementation file //// server program owner dialog initialization BOOL CUDPServerDlg :: OnInitDialog () {CDialog :: OnInitDialog (); // Set the icon for this dialog the framework does this automatically // when the application's main window is not a dialogSetIcon (m_hIcon, TRUE).; // SET BIG ICONSETICON (M_HICON, FALSE); // SET SMALL ICON // Gets the IP address of the local machine, the machine name, and display char hostname [100] on the interface; CHAR HOSTIP [50]; if (Unergyk :: GetHostInfo (hostIP, hostName)) {mEditHostName.SetWindowText (hostName); mEditHostIP.SetWindowText (hostIP);} // server receives data mServerInfo.Format ( "This is a UDP server, listening to port 10025." on port 10025) Updatedata (false); / / Set the server to receive the port number for data, then create the receiving socketmudpManager.setLocalPort (10025); if (MudpManager.createReceiver ()) {// Start data receiving thread mudpManager.startReceiving (); } Return True; // Return True Unless} // udpclientdlg.h: Header File // Class CudpClientdlg: Publi C cdialog {protected: cdialog {protected: // Other Member Definition (omitted) // ...}; // udpclientdlg.cpp: Implementation File /// Client Program Main Dialog Box Initial CudpClientdlg :: OnNInitdialog () { CDIALOG :: OnNIndDialog (); // set the application's automatic or// gen the application's main window is not a dialogseticon (m_hicon, true); // set big iconseticon (m_hicon, false); / / Set small icon // Gets the IP address of the local machine, the machine name, and display char hostname [100] on the interface; CHAR HOSTIP [50]; if (UnetWork:: gethostinfo (Hostip, hostname)) {Medithostname.SetWindowText Hostname); Medithostip.SetWindowText (Hostip); // The client receives data MudpManager.setlocalPort on the 10026 port;
// Create a receiving socketif (MudpManager.createReateiver ()) {// launch data receiving thread mudpManager.StartReceiving ();} // Create a sended socketmudpManager.createsender (); return true; // return true unless a set The "Send" button of the "Send" button on the network to a control} // client void cudpclientdlg :: OnButtonsend () {updateData (TRUE); // Set the IP address of the remote end, data receiving port number MudpManager.SetTarget (Mtargetip) ); mudpManager.SetTargetPort (Word) MtargetPort); / / Send data // Send data // to remote ends specified as 1, indicating that the remote end receives a feedback message MudpManager.send ( "1" mmsg2send, mmsg2send.getLength () 1);} Tip: The full implementation of the UDP Transfer Demo program is provided in the SourceCodes / Chapter03 / UdpDemo directory of this book. Where udpserver is a server program, udpclient is a client program. Open WSCLIENTSERVER.DSW You can browse UDPServer and UDPClient at the same time.
3.1.2 IP Multicast Technology Multicast Technology is considered to be one of the most exciting network technologies that occur after WWW technology promotion. Multicast is a network technology that allows one or more senders to send a single data packet to multiple recipients. The multicast source sends the packet to a specific multicast group, and only the host added to the multicast group can receive these packets. Multicast can greatly save network bandwidth, because no matter how many target addresses, only single packets are transmitted on any link of the entire network. The data transfer process of unicast and multicast is different from Figure 3.10. Figure 3.10 Unicast Transfer of Data Transfer Process Unicast: Network Connections in Point-to-Point Point between the sender and each recipient. If a sender transmits the same data to multiple recipients, it must be replicated into multiple copies accordingly. If there is a large number of hosts wish to get the same copy of the packet, the sender will result in heavy, delayed long, network congestion; to ensure a certain quality of service needs to increase hardware and bandwidth. Multicast Transport: A point-to-multi-point network connection is implemented between the sender and each recipient. If a sender transmits the same data to multiple recipients, it is possible to deliver a packet. The multicast increases the transmission efficiency of the data, reducing the possibility of congestion in the backbone network. Broadcast transmission: refers to the broadcast packet in IP subnet, all hosts inside the subnet will receive these packets, regardless of whether they are not happy to receive. The broadcast range is very small, only in the local subnet, because the router typically blocks broadcast communication. Broadcast transmission increases non-recipient's overhead. Currently, the most widely used multicast technology is IP multicast technology. IP Multicast Technology is a technique that is used to optimize the use of network resources, usually used in a multi-point mode of operation, which is an extension of standard IP network layer protocol technology. From Steve Deering, the definition in the RFC 1112 ("Host Extensions for IP Multicasting"), which is proposed in 1989, can be seen, the core idea of IP multicast is: send data (UDP package) to a group of hosts through an IP address; send Just send information to a group address, the recipient can receive information only; all the recipients receive the same data stream; the members of the group are dynamic, and can join or join or add or Exit; Each host can join multiple groups simultaneously, each multicast address can have multiple data streams on different ports or different sockets, while many actual applications can share a group address. IP multicast techniques can effectively avoid the reproduction of the broadcast storm that may be caused, and can break through the router's limit and transfer the packet to other network segments. The IP address scheme is specifically scheduted for multicast. In IPv4, the IPv4 is the D-class address, and the range is 224.0.0.0 to 239.255.255.255, and divide the D address into a local link multicast address, reserved multicast address , Administrative rights multicast address, etc., allocated as follows: Local link address: 224.0.0.0 ~ 224.0.0.255 for local area networks, routers do not forward IP packets within this range. Reserved multicast addresses: 224.0.1.0 ~ 238.255.255.255 for global or network protocols. Administration address: 239.0.0 ~ 239.255.255.255, the internal use of the organization is used to limit the range of multicast. From the perspective of multimedia applications, the use of IP multicast technology is particularly important for multi-point real-time monitoring of network video.
This section will implement an IP multicast demo MulticastDemo, which includes two parts: servers and clients. Their program interface is shown in Figure 3.11. Figure 3.11 Multicast Transport Demo Demo MulticastDemo's demo procedure is as follows: (1) Run the server and client two-part programs. To demonstrate multicast features, client programs can run multiple processes, each process distinguish between PID; they are added to the same multicast group 239.8.8.8, and each of them launches a data receiving thread. (2) Edit the message content you want to send on the server program interface, then click the "Send" button to send data. (3) All running client program processes will receive information sent by the server and pop up the message box as shown in Figure 3.12. (Assuming that two client program processes are running, their PID is 1608 and 1716.) Figure 3.12 Multicast Transport client process received message box prompts after the data is displayed: Before playing a demo, please confirm your machine. Install a NIC and the local area network is connected properly.
The multicast actually uses the UDP protocol to transmit data. MulticastDemo designed a CMUlticastAdmin class specifically responsible for the sending and reception of multicast data (data reception using a separate sub-thread). (CMULTICASTADMIN is actually overwriting by CudpManager class, which is very similar to the implementation of these two classes.
) CMulticastAdmin class definition and implementation of the following: //// CMulticastAdmin.h // #ifndef __H_CMulticastAdmin __ # define __H_CMulticastAdmin__ class CMulticastAdmin {private: SOCKET mSckReceiver; // for reception SocketSOCKET mMulticaster; // multicast transmission of SocketDWORD mMulticastIP; // Multicast IP address (using host byte order) Word mmulticast; // multicast port number BOOL MISRECEIVING; // Data is receiving the tag handle mrcvthread; // data receiving thread handle PUBLIC: cmulticastadmin (); ~ Cmulticastadmin (); // Setting / Get Multicast IP Address Void SetMultiTiP (DWORD INIP); Void SetMulticastip (const char * inip); void getMulticastip (char * outip); // Setting / get multicast port number void SetMulticastPort (WORD inPort); WORD GetMulticastPort (void); // create / destroy multicast with SocketBOOL CreateMulticaster (void); void DeleteMulticaster (void); // create / destroy SocketBOOL createReceiver (void) for reception; void DeleteReceiver (void); // (multicast) transmission data BOOL multicast (const char * inBuffer, long inLength); // start / stop data receiving thread BOOL StartReceiving (void); void StopReceiving (void); private: void ReceivingLoop (void); // Data Receiving Process Static DWORD WINAPI ReceivingThrd (Void * PPARAM); // Receive thread executive}; #ENDIF //// __H_CMulticastAdmin__ //// CMulticastAdmin.cpp // #include "stdafx.h" #include "CMulticastAdmin.h" #ifdef _DEBUG # define new DEBUG_NEW # undef THIS_FILEstatic char THIS_FILE [] = __FILE __; # endif / CMulticastAdmin :: CMulticastAdmin () {// initialize mSckReceiver = INVALID_SOCKET; mMulticaster = INVALID_SOCKET; // Multicast IP: from 224.0.0.0 to 239.255.255.255mMulticastIP = 0xef080808; // 239.8.8.8mMulticastPort = 10018; mIsReceiving = FALSE; mRcvThread = NULL;} CMulticastAdmin: : ~ Cmulticastadmin () {// Destroy all the useful-used socketdeletemulticaster (); deleteReceiver (); stopReceiving ();} // sets multicast IP address void cmulticastadmin :: setMultiP (dword inip) {mmulticastip = inIP;
} // Get the multicast IP address DWORD CMulticastAdmin :: GetMulticastIP (void) {return mMulticastIP;} // set the multicast IP address void CMulticastAdmin :: SetMulticastIP (const char * inIP) {mMulticastIP = ntohl (inet_addr (inIP)); } // Get multicast IP address void cmulticastadmin :: getMulticastip (char * outip) {if (outip) {structure in_addr in; in .s_un.s_addr = htonl (mmulticastip); char * pstr = inet_ntoa (in); strcpy outIP, pStr);}} // set the multicast port number void CMulticastAdmin :: SetMulticastPort (WORD inPort) {mMulticastPort = inPort;} // Get the multicast port number WORD CMulticastAdmin :: GetMulticastPort (void) {return mMulticastPort;} / / Creating a SocketBool CMULTICASTADMIN :: CreateMulticaster () {DeleteMulticaster () {deletemultesteraster (); // Initialization Socket Library: Use 2.2 version of Winsock DLL WSADATA DATA; int RET = WSAStartup (0x0202, & data); if (RET! = 0) {wsacleanup (); return false;} // Create a socketMULTICASTER = Socket (AF_INET, SOCK_DGRAM, 0) using UDP protocol; if (mmulticaster == invalid_socket) {wsacleanup (); Return False;} // Setting parameters on the Socket: Allow the address to be multiplexed Bool flag = true; ret = setsockopt (Mmulticaster, SOL_Socket, SO_REUSEADDR, (Char *) & flag, sizeof (flag)); // Bind SO cket to the multicast port number SOCKADDR_IN addr; ZeroMemory (& addr, sizeof (addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; // do not care about the network card address addr.sin_port = htons (mMulticastPort); ret = bind (mMulticaster, (struct sockaddr *) & addr, sizeof (addr)); return TRUE;} // destruction of multicast transmission Socketvoid CMulticastAdmin :: DeleteMulticaster (void) {if (! mMulticaster = INVALID_SOCKET) {closesocket (mMulticaster ); mmulticaster = invalid_socket; wsacleanup ();}} // Create a receiving socket (need to join the specified multicast group! Bool CMULTICASTADMIN :: CreateReceiver () {deleteReceiver () {deleteReceiver (); // Initialization Socket Library: Using 2.2 version of Winsock DLLWSADATA DATA; int RET = WSAStartup (0x0202, & data); if (RET! =
0) {wsacleanup (); return false;} // Create a socketmsckreceiver = socket (AF_INET, SOCK_DGRAM, 0) using UDP protocol; if (msckreceiver == invalid_socket) {wsacleanup (); returnaf (} // Setting parameters on the Socket: Allow addresses to multiplex Bool flag = true; ret = setsockopt (MsckReceiver, SOL_SOCKET, SO_REUSEADDR, (CHAR *) & flag, sizeof (flag)); // Binds SOCKET to multicast port slogue SOCKADDR_IN Addr; ZeroMemory (& addr, sizeof (addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; // do not care card address addr.sin_port = htons (mMulticastPort); ret = bind (mSckReceiver, (struct sockaddr *) & addr, sizeof (addr)); // the Socket joined the multicast group (in order to receive multicast data) struct ip_mreq mreq; mreq.imr_multiaddr.s_addr = htonl (mMulticastIP); mreq.imr_interface.s_addr = INADDR_ANY; ret = setsockopt (mSckReceiver, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) & mreq, sizeof (mreq)); return TRUE;} // receiving destruction of Socketvoid CMulticastAdmin :: DeleteReceiver (void) {if (! mSckReceiver = INVALID_SOCKET) {closesocket (mSckReceiver) Msckreceiver = invalid_socket; wsacleanup ();}} // Multicast Send Data Bool CMULTICASTADMIN :: Multicast (const char * Inbuffer, lon g inLength) {SOCKADDR_IN addr; memset ((char *) & addr, 0, sizeof (addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl (mMulticastIP); addr.sin_port = htons (mMulticastPort); / / Send data INT VAL = Sendto (Mmulticaster, Inbuffer, INLENGTH, 0, (SockAddr *) & addr,} // start data reception thread BOOL CMulticastAdmin :: StartReceiving (void) {if (mSckReceiver == INVALID_SOCKET) {createReceiver ();} if (mSckReceiver = INVALID_SOCKET!) {if (mIsReceiving) {return TRUE;} DWORD threadID = 0; mRcvThread = CreateThread (NULL , 0, Receivingthrd, this, 0, & threadid; Return (mrcvthread! =
NULL);} Return False;} // Stop Data Receive Thread Void CMULTICASTADMIN :: StopReceiving (void) {if (misreceiving) {// Destroy the receiving socket, make the reception function fail or disengaged DeleteReceiver (); // Waiting receiving thread completely out if (mRcvThread = NULL!) {WaitForSingleObject (mRcvThread, INFINITE); mRcvThread = NULL;}}} // executable data reception thread (actual call function of this class ReceivingLoop) DWORD WINAPI CMulticastAdmin :: ReceivingThrd ( void * pParam) {ASSERT (pParam); CMulticastAdmin * pController = (CMulticastAdmin *) pParam; pController-> ReceivingLoop (); return 0;} // data receiving process void CMulticastAdmin :: ReceivingLoop (void) {struct sockaddr_in addr_cli; int addr_cli_len = sizeof (addr_cli); char buffer [1024]; // data receiving buffer long bytes = 0; mIsReceiving = TRUE; while (mIsReceiving) {// wait to receive data int addr_cli_len = sizeof (addr_cli); bytes = recvfrom (mSckReceiver (char *) Buffer, 1024, (lpsockaddr) & addr_cli, (int *) & addr_cli_len); if (bytes == Socket_ERROR || Bytes == 0) {MISRECEIVING = false;} else {// Get senders IP address buffer [bytes] = '/ 0'; char * pstr = inet_ntoa (addr_cli.sin_addr); // Pop up a message box, display the received data content cstring msg; msg.format ("Current PID:% D / NRECEIVE FROM% S / NCONTENT:% S ", getCurrentProcessId (), pstr, buffer; AFXMessageBox (MSG);}}} Reconfers the specific implementation of server program MulticastServer and client programs MulticastClient. They are all MFC programs based on dialog and are defined in their respective master dialog classes. Examples of CMUlticastAdmin classes. Then, in the initialization function of the dialog, a series of operations, including creating a multicast transmission / receiving socket, starting the data receiving thread, and the like.
// MulticastServerDlg.h: header file // class CMulticastServerDlg: public CDialog {protected: CMulticastAdmin mMulticaster; // definition of other members (not) // ......}; // MulticastServerDlg.cpp: implementation file // CMulticastServerDlg :: CMulticastServerDlg ( CWnd * pParent / * = NULL * /): CDialog (CMulticastServerDlg :: IDD, pParent) {// {{AFX_DATA_INIT (CMulticastServerDlg) mMsg = _T ( "! Multicast Message> Hi, DirectShow"); //}} AFX_DATA_INIT / / Note that LoadIcon does not require a subsequent DestroyIcon in Win32m_hIcon = AfxGetApp () -> LoadIcon (IDR_MAINFRAME);} // multicast server initialization program main dialog BOOL CMulticastServerDlg :: OnInitDialog () {CDialog :: OnInitDialog (); // set the icon for this dialog. The framework does this automatic or //hen the application's main window is not a dialogseticon (m_hicon, true); // set big iconseticon (m_hicon, false); // set small icon // On the interface, the multicast group IP address, port number and other information MStaticinfo.SetWindowText ("MultiCast IP: 239.8.8.8 Port: 10018"); MMUlticaster.SetMultiTip ("239.8.8.8"); // Creating SocketMUlticaster for multicast transmission .Createmulticaster (); Return TR UE; // Return True UnsS You Set The Focus To A Control} The response function of the "Send" button on the server program interface void cmulticastServerdlg :: onButtonsend () {updata (); // Send a message to the multicast group mMulticaster.Multicast (mMsg, mMsg.GetLength ());} // MulticastClientDlg.h: header file // class CMulticastClientDlg: public CDialog {protected: CMulticastAdmin mReceiver; // definition of other members (not)} // ......; / / MulticastClientDlg.cpp: implementation file //// initialization BOOL client program's main dialog CMulticastClientDlg :: OnInitDialog () {CDialog :: OnInitDialog (); // Set the icon for this dialog the framework does this automatically //. When a application's main window is not a dialogseticon (m_hicon, true); // set big iconseticon (m_hicon, false);