看流星社区

 找回密码
 注册账号
查看: 1940|回复: 0

WSAAsyncSelect模型

[复制链接]

该用户从未签到

发表于 2017-6-2 11:07:42 | 显示全部楼层 |阅读模式
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(&amp;sockAddr, 0, sizeof(sockAddr));
                        int nSockAddrLength = sizeof(sockAddr);
                        ::getpeername(s, (sockaddr*)&amp;sockAddr, &amp;nSockAddrLength);

                        int nPeerPort = ntohs(sockAddr.sin_port);
                        CString strIP = inet_ntoa(sockAddr.sin_addr);  // strIP

                        //获得主机名称
                        DWORD dwIP = ::inet_addr(strIP);
                        hostent* pHost = ::gethostbyaddr((LPSTR)&amp;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, &amp;wsaData);
        //显示对话框
        CMainDialog dlg;
        m_pMainWnd = &amp;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*)&amp;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()
};
点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小黑屋|手机版|Archiver|看流星社区 |网站地图

GMT+8, 2024-3-19 10:46

Powered by Kanliuxing X3.4

© 2010-2019 kanliuxing.com

快速回复 返回顶部 返回列表