当前位置: 首页 > 编程笔记 >

C++之WSAAsyncSelect模型实例

宋飞文
2023-03-14
本文向大家介绍C++之WSAAsyncSelect模型实例,包括了C++之WSAAsyncSelect模型实例的使用技巧和注意事项,需要的朋友参考一下

本文实例讲述了C++中WSAAsyncSelect模型的用法。分享给大家供大家参考。具体实现方法如下:

TCPServer.cpp源文件如下:

#include "TCPServer.h"  

#include "resource.h"  

  

#define WM_SOCKET WM_USER+1  

  

CMyApp theApp;  

  

BOOL CMyApp::InitInstance()  

{  

    //初始化套接字  

    WSADATA wsaData;  

    WORD wVersionRequested = MAKEWORD(2,0);  

    ::WSAStartup(wVersionRequested, &wsaData);  

    //显示对话框  

    CMainDialog dlg;  

    m_pMainWnd = &dlg;  

    dlg.DoModal();  

    //释放套接字  

    ::WSACleanup();  

    return FALSE;  

}  

  

//CMainDialog  

CMainDialog::CMainDialog(CWnd* pParentWnd):CDialog(IDD_MAINDIALOG,pParentWnd)  

{  

  

}  

BEGIN_MESSAGE_MAP(CMainDialog, CDialog)  

ON_BN_CLICKED(IDC_START, OnStart)  

ON_BN_CLICKED(IDC_CLEAR, OnClear)  

ON_MESSAGE(WM_SOCKET, OnSocket)  

END_MESSAGE_MAP()  

  

void CMainDialog::OnCancel()  

{  

    this->CloseAllSocket();  

    CDialog::OnCancel();  

}  

  

BOOL CMainDialog::OnInitDialog()  

{  

    CDialog::OnInitDialog();  

  

    //设置图标  

    SetIcon(theApp.LoadIconA(IDI_MAIN), FALSE);  

  

    //创建状态栏并设置其属性  

    m_bar.Create(WS_CHILD|WS_VISIBLE|SBS_SIZEGRIP, CRect(0,0,0,0), this, 101);  

    m_bar.SetBkColor(RGB(0xa6, 0xca, 0xfa));  

    int arWidth[]={200,-1};  

    m_bar.SetParts(2, arWidth);  

    m_bar.SetText("windows程序设计", 1, 0);  

    m_bar.SetText("空闲", 0, 0);  

    //关联列表控件  

    m_listInfo.SubclassDlgItem(IDC_LIST, this);  

  

    //初始化套接字和连接列表  

    m_socket = INVALID_SOCKET;  

    m_nClient = 0;  

  

    //取得本机IP,在状态栏中显示  

    char szHostName[MAX_PATH] = {0};  

    ::gethostname(szHostName, MAX_PATH);  

    hostent *pHost = gethostbyname(szHostName);  

    if (pHost != NULL)  

    {  

        CString strIP;  

        in_addr* addr = (in_addr*)*pHost->h_addr_list;  

        strIP.Format("本机IP:%s",inet_ntoa(addr[0]));  

        m_bar.SetText(strIP, 0, 0);  

    }  

    return TRUE;  

}  

  

BOOL CMainDialog::CreateAndListen(int nPort)  

{  

    if (m_socket == INVALID_SOCKET)  

    {  

        ::closesocket(m_socket);  

    }  

    //创建套接字  

    m_socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  

    if (m_socket == INVALID_SOCKET)  

    {  

        return FALSE;  

    }  

    //绑定端口  

    sockaddr_in sin;  

    sin.sin_family = AF_INET;  

    sin.sin_port = htons(nPort);  

    //sin.sin_addr.S_un.S_addr = INADDR_ANY;  

    sin.sin_addr.s_addr = INADDR_ANY;  

    int nErr = GetLastError();  

    if (::bind(m_socket, (sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR)  

    {  

        nErr = GetLastError();  

        return FALSE;  

    }  

    ::WSAAsyncSelect(m_socket, m_hWnd, WM_SOCKET, FD_ACCEPT|FD_CLOSE|FD_READ);  

  

    //进入监听模式  

    ::listen(m_socket, 5);  

  

    return TRUE;  

}  

  

BOOL CMainDialog::AddClient(SOCKET s)  

{  

      

    if (m_nClient < MAX_SOCKET)  

    {  

        m_arClient[m_nClient++] = s;  

        return TRUE;  

    }  

    return FALSE;  

      

}  

  

void CMainDialog::RemoveClient(SOCKET s)  

{  

    BOOL bFound = FALSE;  

    int i;  

    for (i=0;i<m_nClient;i++)  

    {  

        if (m_arClient[i] == s)  

        {  

            bFound = TRUE;  

            break;  

        }  

    }  

  

    //找到  

    if (bFound)  

    {  

        m_nClient--;  

        for (int j=i;j<m_nClient;j++)  

        {  

            m_arClient[j] = m_arClient[j+1];  

        }  

    }  

}  

void CMainDialog::CloseAllSocket()  

{  

    if (m_socket != INVALID_SOCKET)  

    {  

        ::closesocket(m_socket);  

        m_socket = INVALID_SOCKET;  

    }  

    for (int i=0;i<m_nClient;i++)  

    {  

        ::closesocket(m_arClient[i]);  

    }  

    m_nClient = 0;  

}  

  

void CMainDialog::OnStart()  

{  

    if (m_socket == INVALID_SOCKET) //开启服务  

    {  

        CString strPort;  

        GetDlgItem(IDC_PORT)->GetWindowText(strPort);  

        int nPort = atoi(strPort);  

        if (nPort < 1 || nPort >65535)  

        {  

            MessageBox("port error");  

            return;  

        }  

        //创建套接字  

        if (!this->CreateAndListen(nPort))  

        {  

            MessageBox("create socket error");  

            return;  

        }  

        //设置控件状态  

        GetDlgItem(IDC_START)->SetWindowTextA("停止服务");  

        m_bar.SetText("正在监听...", 0, 0);  

        GetDlgItem(IDC_PORT)->EnableWindow(FALSE);  

    }  

    else //关闭服务  

    {  

        CloseAllSocket();  

        GetDlgItem(IDC_START)->SetWindowTextA("开启服务");  

        m_bar.SetText("空闲", 0, 0);  

        GetDlgItem(IDC_PORT)->EnableWindow(TRUE);  

    }  

    return ;  

}  

void CMainDialog::OnClear()  

{  

    m_listInfo.ResetContent();  

    return ;  

}  

  

long CMainDialog::OnSocket(WPARAM wParam, LPARAM lParam)  

{  

    //得到句柄   

    SOCKET s = wParam;  

    //查看是否出错  

    if (WSAGETSELECTERROR(lParam))  

    {  

        RemoveClient(s);  

        ::closesocket(s);  

        return 0;  

    }  

    //处理发生的事件  

    switch (WSAGETSELECTEVENT(lParam))  

    {  

    case FD_ACCEPT: //监听到有套接字中有连接进入  

        {  

            MessageBox("server:accept");  

            if (m_nClient < MAX_SOCKET)  

            {  

                SOCKET client = ::accept(s, NULL, NULL);  

                this->AddClient(client);  

            }  

            else  

            {  

                MessageBox("too many connection");  

            }  

        }  

        break;  

    case FD_CLOSE:  

        {  

            MessageBox("server:close");  

            RemoveClient(s);  

            closesocket(s);  

        }  

        break;  

    case FD_READ: //接收到对方发来的数据包  

        {  

            MessageBox("server:read");  

            //得到对方的地址  

            sockaddr_in sockAddr;  

            memset(&sockAddr, 0, sizeof(sockAddr));  

            int nSockAddrLength = sizeof(sockAddr);  

            ::getpeername(s, (sockaddr*)&sockAddr, &nSockAddrLength);  

  

            int nPeerPort = ntohs(sockAddr.sin_port);  

            CString strIP = inet_ntoa(sockAddr.sin_addr);  // strIP  

  

            //获得主机名称  

            DWORD dwIP = ::inet_addr(strIP);  

            hostent* pHost = ::gethostbyaddr((LPSTR)&dwIP, 4, AF_INET);  

            char szHostName[256]={0};  

            strncpy(szHostName, pHost->h_name, 256);  

  

            //得到网络数据  

            char szContent[1024]={0};  

            ::recv(s, szContent, 1024, 0);  

  

            //显示  

            CString strItem = CString(szHostName) + "[" + strIP + "]:" + CString(szContent);  

            m_listInfo.InsertString(0, strItem);  

        }  

        break;  

    }  

    return 0;  

}

TCPServer.h头文件如下:

#include <afxwin.h>  

#include <afxext.h>  //CStatusBar  

#include <WinSock2.h>  

#include <afxcmn.h>  

  

#pragma comment(lib, "WS2_32.lib")  

#define  MAX_SOCKET 56 //最大客户量  

  

class CMyApp:public  CWinApp  

{  

public:  

    BOOL InitInstance();  

};  

  

//CMainDialog  

class CMainDialog:public CDialog  

{  

public:  

    CMainDialog(CWnd* pParentWnd=NULL);  

  

protected:  

    virtual BOOL OnInitDialog();  

    virtual void OnCancel();  

    //开启或停止服务  

    afx_msg void OnStart();  

    afx_msg void OnClear();  

    afx_msg long OnSocket(WPARAM wParam, LPARAM lParam);  

  

    BOOL CreateAndListen(int nPort);  

  

    //向客户连接列表中加一个客户  

    BOOL AddClient(SOCKET s);  

    //从客户连接列表中移除一个客户  

    void RemoveClient(SOCKET s);  

    //关闭所有连接  

    void CloseAllSocket();  

  

protected:  

    SOCKET m_socket;  

    //两个子窗口控件  

    CListBox m_listInfo;  

    CStatusBarCtrl m_bar;  

  

    //客户连接列表  

    SOCKET m_arClient[MAX_SOCKET]; //套接字列表  

    int m_nClient; //上述数组的大小  

  

    DECLARE_MESSAGE_MAP()  

};

TCPClient.cpp源文件如下:

#include "TCPClient.h"  

#include "resource.h"  

  

#define WM_SOCKET WM_USER+1  

  

CMyApp theApp;  

  

BOOL CMyApp::InitInstance()  

{  

    //初始化套接字  

    WSADATA wsaData;  

    WORD wVersionRequested = MAKEWORD(2,0);  

    ::WSAStartup(wVersionRequested, &wsaData);  

    //显示对话框  

    CMainDialog dlg;  

    m_pMainWnd = &dlg;  

    dlg.DoModal();  

    //释放套接字  

    ::WSACleanup();  

    return FALSE;  

}  

  

//CMainDialog  

CMainDialog::CMainDialog(CWnd* pParentWnd):CDialog(IDD_MAINDIALOG,pParentWnd)  

{  

  

}  

BEGIN_MESSAGE_MAP(CMainDialog, CDialog)  

    ON_BN_CLICKED(IDC_CONNECT, OnConnect)  

    ON_BN_CLICKED(IDC_SEND, OnSend)  

    ON_MESSAGE(WM_SOCKET, OnSocket)  

END_MESSAGE_MAP()  

  

void CMainDialog::OnCancel()  

{  

      

    CDialog::OnCancel();  

}  

  

BOOL CMainDialog::OnInitDialog()  

{  

    CDialog::OnInitDialog();  

  

    //设置图标  

    SetIcon(theApp.LoadIconA(IDI_MAIN), FALSE);  

  

    //关联控件  

    m_edit_text.SubclassDlgItem(IDC_EDIT_CONTENT, this);  

    //状态栏  

    m_bar.Create(WS_CHILD|WS_VISIBLE|SBS_SIZEGRIP, CRect(0, 0, 0,0), this, NULL);  

    int nWidth[]={100,-1};  

    m_bar.SetParts(2, nWidth);  

    m_bar.SetText("windows程序设计", 1, 0);  

    m_bar.SetText("空闲", 0, 0);  

  

    GetDlgItem(IDC_ADDR)->SetWindowTextA("192.168.19.143");  

    GetDlgItem(IDC_PORT)->SetWindowTextA("9999");  

  

    //  

    m_socket = INVALID_SOCKET;  

      

    return TRUE;  

}  

void CMainDialog::AddStringToList(CString strText)  

{  

    CString strContent;  

    GetDlgItem(IDC_EDIT_CONTENT)->GetWindowText(strContent);  

    GetDlgItem(IDC_EDIT_CONTENT)->SetWindowText(strContent+strText);  

  

}  

long CMainDialog::OnSocket(WPARAM wParam, LPARAM lParam)  

{  

    SOCKET  s = wParam;  

    if (WSAGETSELECTERROR(lParam))  

    {  

        ::closesocket(m_socket);  

        m_socket = INVALID_SOCKET;  

        return 0;  

    }  

    switch (WSAGETSELECTEVENT(lParam))  

    {  

    case FD_READ:  

        {  

            MessageBox("client:read");  

            char szText[1024]={0};  

            ::recv(s, szText, 1024, 0);  

            AddStringToList(CString(szText)+"\r\n");  

        }  

        break;  

    case FD_CONNECT:  

        {  

            MessageBox("client:connect");  

            GetDlgItem(IDC_CONNECT)->SetWindowTextA("断开连接");  

            GetDlgItem(IDC_ADDR)->EnableWindow(FALSE);  

            GetDlgItem(IDC_PORT)->EnableWindow(FALSE);  

            GetDlgItem(IDC_TEXT)->EnableWindow(TRUE);  

            GetDlgItem(IDC_SEND)->EnableWindow(TRUE);  

            m_bar.SetText("已经连接到服务器", 0, 0);  

        }  

        break;  

    case FD_CLOSE:  

        {  

            MessageBox("client:close");  

            OnConnect();  

        }  

        break;  

    }  

    return 0;  

}  

  

BOOL CMainDialog::Connect(LPCTSTR pszRemoteAddr, u_short nPort)  

{  

    //创建套接字  

    m_socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  

    if (INVALID_SOCKET == m_socket)  

    {  

        return FALSE;  

    }  

    ::WSAAsyncSelect(m_socket, m_hWnd, WM_SOCKET, FD_READ|FD_WRITE|FD_CONNECT|FD_CLOSE);  

  

    ULONG uAddr = ::inet_addr(pszRemoteAddr);  

    if (uAddr == INADDR_NONE)  

    {  

        //不是IP地址,就认为是主机名称  

        //从主机名得到IP  

        hostent* pHost = ::gethostbyname(pszRemoteAddr);  

        if (pHost == NULL)  

        {  

            ::closesocket(m_socket);  

            m_socket = INVALID_SOCKET;  

            return FALSE;  

        }  

        uAddr = ((struct in_addr*)*(pHost->h_addr_list))->s_addr;  

    }  

  

    //填写服务器信息  

    sockaddr_in remote;  

    remote.sin_family = AF_INET;  

    remote.sin_addr.S_un.S_addr = uAddr;  

    remote.sin_port = ::htons(nPort);  

    //连接  

    ::connect(m_socket, (sockaddr*)&remote, sizeof(sockaddr));  

    return TRUE;  

}  

  

void CMainDialog::OnConnect()  

{  

    if (INVALID_SOCKET == m_socket) //连接服务器  

    {  

        CString strAddr;  

        GetDlgItem(IDC_ADDR)->GetWindowText(strAddr);  

        if (strAddr.IsEmpty())  

        {  

            MessageBox("the servers IP is empty");  

            return;  

        }  

        CString strPort;  

        GetDlgItem(IDC_PORT)->GetWindowTextA(strPort);  

        int nPort = atoi(strPort);  

        if (nPort < 1 || nPort > 65535)  

        {  

            MessageBox("port error");  

            return;  

        }  

        if (Connect(strAddr, nPort) == FALSE)  

        {  

            MessageBox("connect to servers error...");  

            return;  

        }  

        //设置用户界面  

        GetDlgItem(IDC_CONNECT)->SetWindowText("取消");  

        m_bar.SetText("正在连接..", 0, 0);  

          

    }  

    else //断开服务器  

    {  

        ::closesocket(m_socket);  

        m_socket = INVALID_SOCKET;  

        //设置用户界面  

        GetDlgItem(IDC_CONNECT)->SetWindowTextA("连接服务器");  

        m_bar.SetText("空闲", 0, 0);  

        GetDlgItem(IDC_ADDR)->EnableWindow(TRUE);  

        GetDlgItem(IDC_PORT)->EnableWindow(TRUE);  

        GetDlgItem(IDC_SEND)->EnableWindow(FALSE);  

        GetDlgItem(IDC_TEXT)->EnableWindow(FALSE);  

    }  

      

    //this->Connect(szAddr, )  

}  

void CMainDialog::OnSend()  

{  

    CString strSendContent;  

    GetDlgItem(IDC_TEXT)->GetWindowTextA(strSendContent);  

    ::send(m_socket, strSendContent, strSendContent.GetLength(), 0);  

    GetDlgItem(IDC_TEXT)->SetWindowTextA("");  

}

TCPClient.h头文件如下:

#include <afxwin.h>  

#include <afxext.h>  //CStatusBar  

#include <WinSock2.h>  

#include <afxcmn.h>  

  

#pragma comment(lib, "WS2_32.lib")  

#define  MAX_SOCKET 56 //最大客户量  

  

class CMyApp:public  CWinApp  

{  

public:  

    BOOL InitInstance();  

};  

  

  

//CMainDialog  

class CMainDialog:public CDialog  

{  

public:  

    CMainDialog(CWnd* pParentWnd=NULL);  

  

protected:  

    virtual BOOL OnInitDialog();  

    virtual void OnCancel();  

    ////开启或停止服务  

    //afx_msg void OnStart();  

    afx_msg void OnSend();  

    afx_msg long OnSocket(WPARAM wParam, LPARAM lParam);  

    void OnConnect();  

  

    BOOL Connect(LPCTSTR pszRemoteAddr, u_short nPort);  

    SOCKET m_socket;  

  

    // 控件  

    CStatusBarCtrl m_bar;  

    CEdit m_edit_text;  

  

    void AddStringToList(CString strText);  

    //BOOL CreateAndListen(int nPort);  

  

    ////向客户连接列表中加一个客户  

    //BOOL AddClient(SOCKET s);  

    ////从客户连接列表中移除一个客户  

    //void RemoveClient(SOCKET s);  

    ////关闭所有连接  

    //void CloseAllSocket();  

  

  

    DECLARE_MESSAGE_MAP()  

};

希望本文所述对大家的C++程序设计有所帮助。

 类似资料:
  • 本文向大家介绍C++中I/O模型之select模型实例,包括了C++中I/O模型之select模型实例的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了C++中I/O模型的select模型用法。分享给大家供大家参考。具体实现方法如下: 效果如下图所示: 希望本文所述对大家的C++程序设计有所帮助。

  • 本文向大家介绍C++设计模式之简单工厂模式实例,包括了C++设计模式之简单工厂模式实例的使用技巧和注意事项,需要的朋友参考一下 问题描述 之前在公司做了一个windows 8平台的阅读器。首先,需要将电子书中的内容渲染到屏幕上,而电子书每一页都包含各种各样的内容,比如:图形、图像和文字等等;不同的内容,就是不同的对象;在将不同的内容渲染到屏幕上之前,就需要new操作,建立不同的对象,然后再在屏幕上

  • 本文向大家介绍C#设计模式之单例模式实例讲解,包括了C#设计模式之单例模式实例讲解的使用技巧和注意事项,需要的朋友参考一下 前言 最近开始花点心思研究下设计模式,主要还是让自己写的代码可重用性高、保证代码可靠性。所谓设计模式,我找了下定义:是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。毫无疑问,设计模式于己于他人于系统都是多赢的;设计模式使代码编制真正工程化;设计模式是软件工

  • 我有类似于这个问题用例 我想检查什么类型的实例变量存储在参数中而不引发异常 我想做的是这样的事情 我如何改变这个实现,使它允许我窥视什么类型的参数是持有的 谢谢你的回答,还有几点 我是C++11所以不能使用variant或any 有没有标准的方法。我想要的是一个实例变量的类,可以是多种类型(有界的),并在阅读它时,检查它是什么类型

  • 本文向大家介绍C#基础之泛型委托实例教程,包括了C#基础之泛型委托实例教程的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了C#中泛型委托的用法,并以示例形式较为详细的进行了用法分析。分享给大家供大家参考之用。具体如下: 首先,泛型委托是委托的一种特殊形式,虽然感觉看上去比较怪异,其实在使用的时候跟委托差不多,不过泛型委托更具有类型通用性。 就拿C#里最常见的委托EventHandler打比

  • 本文向大家介绍C#设计模式之观察者模式实例讲解,包括了C#设计模式之观察者模式实例讲解的使用技巧和注意事项,需要的朋友参考一下 前言 最近开始花点心思研究下设计模式,主要还是让自己写的代码可重用性高、保证代码可靠性。所谓设计模式,我找了下定义:是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。毫无疑问,设计模式于己于他人于系统都是多赢的;设计模式使代码编制真正工程化;设计模式是软