The classic entry of the development network communication in the previous discussion is the asynchronous I / O model of WSaasyncselect, which will discuss the WSAEventSelect asynchronous I / O model.
The WSAEventSelect model is a bit similar to the WSaasyncselect model, and the difference is that he does not respond to the network event in a message map, but is used to respond to the network event in a way for multiple events. Below is a simple server program for a WSAEventSelectSelect model and a multi-thread mechanism, the application based on the MFC standard dialog. Implement a connection request accepted by multiple clients, and record related information about all clients, displayed in the list box.
// serverdlg.cpp: importation file //
#include "stdafx.h" #include "server.h" #include "serverdlg.h"
#ifdef _debug # define new debug_new # undef this_filestatic char this_file [] = __file __; # ENDIF
Socket accept; file: // Used for new connections for new connections WSAEVENT NEWEVENT; file: / / New event corresponding to new sockets socket socket [WSA_MAXIM_WAIT_EVENTS]; file: // Store all generated sets Sign WSAEVENT EVENT [WSA_MAXIMUM_WAIT_EVENTS]; file: // Store all generated event object int eventtotal; File: // created Total number int index; file: // Waiting for the return value of multiple event functions WSANETWORKEVENTS NETWORKEVENTS; File: // Used to receive network event types that occur on a socket and possible error code
/// Caboutdlg Dialog Used for App About
Class Caboutdlg: public cdialog {public: capoutdlg ();
// Dialog Data file: // {{AFX_DATA (Caboutdlg) enum {IDD = IDD_ABOUTBOX}; file: //}} AFX_DATA
// ClassWizard generated virtual function overrides file: // {{AFX_VIRTUAL (CAboutDlg) protected: virtual void DoDataExchange (CDataExchange * pDX); // DDX / DDV support file: //}} AFX_VIRTUAL
// ImplementationProtace: file: // {{AFX_MSG (Caboutdlg) File: //}} AFX_MSG DECLARE_MESSAGE_MAP ()};
Caboutdlg :: Caboutdlg (): cdialog (Caboutdlg :: IDD) {file: // {{AFX_DATA_INIT (Caboutdlg) File: //}} AFX_DATA_INIT}
Void Caboutdlg :: DODATAEXCHANGE (CDataExchange * PDX) {cdialog :: DODATAEXCHANGE (PDX); file: // {{AFX_DATA_MAP (Caboutdlg) file: //}} AFX_DATA_MAP}
Begin_MESSAGE_MAP (Caboutdlg, cdialog) file: // {{AFX_MSG_MAP (Caboutdlg) // no message handlers file: //}} AFX_MSG_MAPEND_MESSAGE_MAP ()
/// Cserververdlg Dialog
CServerDlg :: CServerDlg (CWnd * pParent / * = NULL * /): CDialog (CServerDlg :: IDD, pParent) {file: // {{AFX_DATA_INIT (CServerDlg) // NOTE: the ClassWizard will add member initialization here file: / /}} AFX_DATA_INIT // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_Connectnum = 0; m_NetworkID = 0; EventTotal = 0; for (int i = 0; i
void CServerDlg :: DoDataExchange (CDataExchange * pDX) {CDialog :: DoDataExchange (pDX); file: // {{AFX_DATA_MAP (CServerDlg) // NOTE: the ClassWizard will add DDX and DDV calls here file: //}} AFX_DATA_MAP}
BEGIN_MESSAGE_MAP (CServerDlg, CDialog) file: // {{AFX_MSG_MAP (CServerDlg) ON_WM_SYSCOMMAND () ON_WM_PAINT () ON_WM_QUERYDRAGICON () ON_WM_TIMER () file: //}} AFX_MSG_MAPEND_MESSAGE_MAP ()
/// cserverdlg Message Handlers
Bool CSERVERDLG :: OnNitdialog () {cdialog :: oninitdialog ();
// Add "About ..." Menu Item to System Menu.
// IDM_ABOUTBOX MUST BE IN THE SYSTEM Command Range. Assert ((idm_aboutbox & 0xff0) == idm_aboutbox; assert (idm_aboutbox <0xf000);
CMenu * pSysMenu = GetSystemMenu (FALSE); if (pSysMenu = NULL!) {CString strAboutMenu; strAboutMenu.LoadString (IDS_ABOUTBOX); if {pSysMenu-> AppendMenu (MF_SEPARATOR) (strAboutMenu.IsEmpty ()!); PSysMenu-> AppendMenu ( MF_String, IDM_AboutBox, Straboutmenu);}}
// set the icon for this dialog. The framework does this automatic or //en the application's main window is not a dialog seticon (m_hicon, true); // set big icon seticon (m_hicon, false); // set small icon / / TODO: Add Extra Initialization Here
Wsadata wsadata; int RET; RET; MakeWord (2, 2), & WSADATA); if (RET! = 0) {MessageBox ("Initializing Socket Failed!"); Return False;}
file: // create a socket m_ListenSocket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); if (m_ListenSocket == INVALID_SOCKET) {MessageBox ( "! Creating socket failed"); closesocket (m_ListenSocket); WSACleanup (); return False;}
File: // Binds to the specified port SockAddr_in localaddr; localaddr.sin_family = af_INet; localaddddddddddddddddddddddddddddddddddddddddddddddddr.sin_addr.s_addr = 0;
if (bind (m_ListenSocket, (const struct sockaddr *) & localaddr, sizeof (sockaddr)) == SOCKET_ERROR) {MessageBox ( "bound address failed!"); closesocket (m_ListenSocket); WSACleanup (); return FALSE;} NewEvent = WSACReateEvent (); file: // Create a new event object
File: // Associate the created event object with the socket created in front, and register Network Event Type IF (WSAEventSELECT (M_ListenSocket, NewEvent, fd_accept | fd_close) == SOCKET_ERROR) {MessageBox ("Register Network Event Failed! "); CloseSocket (M_Listensocket); wsacleanup (); returnaf
File: // Let the created socket in the listening status listen (M_Listensocket, 5);
Event [Eventtotal] = newEvent; socket [Eventtotal] = M_Listensocket; EventTotal ;
File: // Set the image list of the List control Hicon Hicon;
m_imagelist.create (16, 16, 0, 4); // 32, 32 for large icons Hicon = AFXGETAPP () -> loading (idi_client_info); m_imagelist.setbkcolor (RGB (248, 232, 224)); m_imagelist.add (Hicon );
pList = (CListCtrl *) GetDlgItem (IDC_CLIENT_INFO); pList-> SetImageList (& m_imagelist, LVSIL_SMALL); pList-> SetBkColor (RGB (248,232,224)); pList-> SetTextBkColor (RGB (248,232,224));
PLIST-> INSERTCOLUMN (0, "Customer Name", LVCFMT_Center, 90, 0); PLIST-> INSERTCOLUMN (1, "Network ID", LVCFMT_Center, 50, 1); PLIST-> InsertColumn (2, "IP Address", LVCFMT_CENTER, 100, 2); PLIST-> INSERTCOLUMN (3, "Login Time", LVCFMT_Center, 120, 3); PLIST-> InsertColumn (4, "Online Time", LVCFMT_Center, 100, 4); SetTimer (1, 1000 NULL);
File: // Start the core processing thread AFXBEGINTHREAD (KernelWorkthread, this, thread_priority_normal);
Return True; // Return True Unless}
void CServerDlg :: OnSysCommand (UINT nID, LPARAM lParam) {if ((nID & 0xFFF0) == IDM_ABOUTBOX) {CAboutDlg dlgAbout; dlgAbout.DoModal ();} else {CDialog :: OnSysCommand (nID, lParam);}}
// if you add a minimize button to your dialog, you will need the code Below // to draw the icon. For mfc Applications Using the document / view model, // this is automaticly done for you by the framework.
Void CServerdlg :: OnPaint () {if (isiconic ()) {CPAINTDC DC (this); // Device Context for Painting
SendMessage (WM_ICONERASEBKGND, (WPARAM) dc.getsafehdc (), 0);
// Center icon in client rectangle int cxIcon = GetSystemMetrics (SM_CXICON); int cyIcon = GetSystemMetrics (SM_CYICON); CRect rect; GetClientRect (& rect); int x = (rect.Width () - cxIcon 1) / 2; int y = (Rect.height () - Cyicon 1) / 2;
// Draw the icon dc.drawicon (x, y, m_hicon);} else {cdialog :: onpaint ();}}
// the system calls this to obtain the cursor to display while the user dress /// the minimized window.hcursor cserverdlg :: ONQUERYDRAGICON () {Return (hcursor) m_hicon;}
File: // Core processing thread, responding and processes various network events uint kernelworkthread (lpvoid pParam) {int Len = sizeof (sockAddr);
CServerDLG * DLG; DLG = (Cserverdlg *) PPARAM;
while (1) {Index = WSAWaitForMultipleEvents (EventTotal, Event, FALSE, WSA_INFINITE, FALSE); WSAEnumNetworkEvents (Socket [Index - WSA_WAIT_EVENT_0], Event [Index - WSA_WAIT_EVENT_0], & NetworkEvents); if (NetworkEvents.lNetworkEvents & FD_ACCEPT) file: / / Connecting event {if (networkEvents.ierrorcode [fd_accept_bit]! = 0) {DLG-> MessageBox ("Accept connection event failed!"); Break;}
Accept = accept (socket [index - wsa_wait_event_0], (strunt socddr *) & (dlg-> clientaddr), & len); if (accept == invalid_socket) {dlg-> MessageBox ("Accept connection failed!"); Break; } IF (EventTotal> WSA_Maximum_Wait_Events) {DLG-> MessageBox ("Connection A number of overflows, refusal!"); Break;}
NEWEVENT = WSACREATEEVENT ();
IF (WSAEventSelect (ACCEPT, NewEvent, fd_read | fd_write | fd_close) == Socket_ERROR) {DLG-> MessageBox ("Register Network Event Failed!"); ClossoSocket (Accept); Break;}
Event [Eventtotal] = newevent; socket [Eventtotal] = Accept; EventTotal ;
IF (NetWorkevents.LnetWorkevents & fd_read) file: // Read data event {if (NetWorkevent.ierrorCode [fd_read_bit]! = 0) {DLG-> MessageBox ("Read Event Failed!"); Break;}
IF (DLG-> OnRecEive (socket [index - wsa_wait_event_0]) == false) {dlg-> messagebox ("Read Data Failed!"); Break;}}
IF (NetWorkevents.LNetworkEvents & fd_close) file: // Close the socket event {if (NetWorkevent.ierrorCode [fd_close_bit]! = 0) {dlg-> MessageBox ("Close Event Failed!"); Break;}
IF (DLG-> OnClose (socket [index - wsa_wait_event_0]) == false) {dlg-> MessageBox ("Close the socket failed!"); Break;}}} Return 0;}
BOOL CSERVERDLG :: OnClose (socket psocket) {INT I, EXITNUM; for (i = 0; i M_ConnectNum -; file: // send to all clients online customer information packets cmd_client_info ClientInfo; ClientInfo.cmd_type = CMD_CLIENT_INFO; ClientInfo.client_num = m_Connectnum; for (i = 0; i <= m_Connectnum; i ) {ClientInfo.Networks_ID [i] = m_ClientInfo [i] .Network_ID; strcpy (ClientInfo.users_name [i], m_ClientInfo [i] .User_Name); strcpy (ClientInfo.clients_ipaddr [i], inet_ntoa (m_ClientInfo [i] .Client_Addr.sin_addr));} for ( i = 0; i <= m_connectnum; i ) {send (m_clientinfo [i] .client_socket, (char *) & clientinfo, sizeof (cmd_client_info), null);} closesocket (psocket); PLIST-> DeleteItem (Exitnum); Return True; BOOL CServerDlg :: OnReceive (SOCKET pSocket) {static char rcvbuf [65535]; file: // buffer receiving int ret; int offset = 0; find_type * pFindType; int i = 0; CTime m_current_time = CTime :: GetCurrentTime () ; Cstring start_time = m_current_time.format ("% c"); cstring networkid; file: // Network ID item of the list box RET = Recv (PSocket, RCVBUF, 65535, 0); if (RET == Operation_ERROR) RETURN FALSE; while (offset memcpy ((struct sockaddr *) & (m_ClientInfo [m_Connectnum] .Client_Addr), (const struct sockaddr *) & clientaddr, sizeof (sockaddr)); m_ClientInfo [m_Connectnum] .Client_Socket = Accept; strcpy (m_ClientInfo [m_Connectnum] .User_Name, HelloResp .user_name); m_ClientInfo [m_Connectnum] .Network_ID = m_NetworkID; m_ClientInfo [m_Connectnum] .Login_Time = m_current_time; send (pSocket, (char *) & HelloResp, sizeof (cmd_hello_resp), NULL); File: / / Send a response message SLEEP (200) to the logged in the client; CMD_Client_info ClientInfo; ClientInfo.cmd_type = cmd_client_info; clientinfo.client_num = m_connectnum 1; for (i = 0; i <= m_Connectnum; i ) {ClientInfo.Networks_ID [i] = m_ClientInfo [i] .Network_ID; strcpy (ClientInfo.users_name [i], m_ClientInfo [i] .User_Name); strcpy (ClientInfo.clients_ipaddr [I], INET_NTOA (m_clientinfo [i] .client_addr.sin_addr);} File: // Send online client information packet for all online clients (i = 0; i <= m_connectnum; i ) {send (m_clientinfo [i] .client_socket, (char *) & clientinfo, sizeof (cmd_client_info), NULL } File: // Refresh the client information list networkid.format ("% d", m_networkid); LVITEM lvinsert; lvinsert.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM; lvinsert.iItem = m_Connectnum; lvinsert.iSubItem = 0; lvinsert.cchTextMax = 20; lvinsert.pszText = HelloResp.user_name; lvinsert.iImage = 0; pList-> InsertItem ( & lvinsert); pList-> SetItemText (m_Connectnum, 1, networkid); pList-> SetItemText (m_Connectnum, 2, inet_ntoa (m_ClientInfo [m_Connectnum] .Client_Addr.sin_addr)); pList-> SetItemText (m_Connectnum, 3, strTime); m_Connectnum ; break; case CMD_ASK: cmd_ask Ask; cmd_ask_resp AskResp; memcpy (& Ask, rcvbuf offset, sizeof (cmd_ask)); offset = sizeof (cmd_ask); AskResp.cmd_type = CMD_ASK_RESP; AskResp.Network_ID = Ask.Network_ID; for (i = 0; I Break; Case CMD_Goodbye: CloseSocket; Break; Default: Break;}} Return True;} Bool CServerdlg :: OnSend (socket psocket) {return true Void CServerdlg :: Onok () {CloseSocket (M_Listensocket); wsacleanup (); cdialog :: onok (); void CServerDlg :: OnTimer (UINT nIDEvent) {CTime m_current_time = CTime :: GetCurrentTime (); CTimeSpan logintimes; CString login_times; CString networkid; file: // network ID list box item for (int i = 0; i // ServerDlg.h: header file // #if! defined (AFX_SERVERDLG_H__B0AA0367_C1F4_11D4_AB1C_0080C8D6FEA5__INCLUDED _) # Define AFX_SERVERDLG_H__B0AA0367_C1F4_11D4_AB1C_0080C8D6FEA5__included_ #if _MSC_VER> 1000 # prgma overce # endif //_MSC_VER> 1000 #include "global.h" /// Cserververdlg Dialog Class CServerdlg: Public CDialog {File: // Global Function Friend Uint KernelWorkthread (LPVOID PPARAM); // ConstructionPublic: ClistCtrl * PList; File: // Client Online Information list box Object CIMAGELIST M_IMAGELIST; Socket M_Listensocket; file: // Used to listen to the port client_info m_clientinfo [max_client_num]; file: // Save the structure of the online client information SOCKADDR_IN ClientAddr; file: // Save the client address INT M_CONNECTNUM File: // Online client number int m_networkid; file: // Return to the client's network ID number BOOL ONSEND (socket psocket); file: // Send a response function for data network event Bool OnRecEut (socket psocket); file: // Receive the response function of the data network event BOOL ONCLOSE (socket psocket); file: // Close the socket Response function for word network event Cserververdlg (CWND * PParent = null); // Standard Constructionor // Dialog Data file: // {{AFX_DATA (CSERVERDLG) ENUM {IDD = IDD_SERVER_DIALOG}; // Note: The classwizard will add data members here file: //}} AFX_DATA // ClassWizard generated virtual function overrides file: // {{AFX_VIRTUAL (CServerDlg) protected: virtual void DoDataExchange (CDataExchange * pDX); // DDX / DDV support file: //}} AFX_VIRTUAL // Implementationprotected: HICON m_hIcon; // Generated message map functions file: // {{AFX_MSG (CServerDlg) virtual BOOL OnInitDialog (); afx_msg void OnSysCommand (UINT nID, LPARAM lParam); afx_msg void OnPaint (); afx_msg HCURSOR OnQueryDragIcon (); virtual void OnOK () AFX_MSG Void ONTIMER (Uint NidEvent); File: //}} AFX_MSG DECLARE_MESSAGE_MAP ()}; File: // {{AFX_INSERT_LOCATION}} // Microsoft Visual C Will Insert Additional Declarations Immediately Before The Previous Line. #ndif //! Defined (AFX_SERVERDLG_H__B0AA0367_C1F4_11D4_AB1C_0080C8D6FEA5__INCLUDED_)