首页 > 代码库 > WSAAsyncSelect模型的小i例子

WSAAsyncSelect模型的小i例子

一个异步模型的聊天程序

服务器端:

自定义消息(放在StdAfx.h文件里面即可)

#define WM_SOCKET WM_USER + 1

然后注册消(在VS2012里面可以自动完成注册和映射 )

afx_msg LRESULT OnSocket(WPARAM wParam, LPARAM lParam);

然后写上 映射

ON_MESSAGE(WM_SOCKET, &CChatDlg::OnSocket)

 对话框的头文件代码

// CChatDlg 对话框
class CChatDlg : public CDialogEx
{
// 构造
public:
    CChatDlg(CWnd* pParent = NULL);    // 标准构造函数

// 对话框数据
    enum { IDD = IDD_MY_DIALOG };

    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持


// 实现
protected:
    HICON m_hIcon;

    // 生成的消息映射函数
    virtual BOOL OnInitDialog();
    afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    DECLARE_MESSAGE_MAP()

public:
    CString m_recv;
    CString m_send;
public:
    SOCKET serverSocket;
    SOCKET sAccept; 
    struct sockaddr_in serverAddress;
    char recvBuff[1024];
    char sendBuff[1024];
    sockaddr_in clientAddr;
public:
    bool initSocket();
    bool recvData();
protected:
    afx_msg LRESULT OnSocket(WPARAM wParam, LPARAM lParam);
public:
    afx_msg void OnBnClickedButtonSend();
};

然后cpp文件

bool CChatDlg::initSocket()
{
    WSADATA wsa;
    if(WSAStartup(MAKEWORD(2,2),&wsa)!=0){
        MessageBox(_T("初始化套接字错误!"));
        return false;
    }

    if((serverSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET){
        MessageBox(_T("创建套接字失败!"));
        return false;
    }
    if (WSAAsyncSelect(serverSocket, this->m_hWnd, WM_SOCKET, FD_ACCEPT)==SOCKET_ERROR)
    {
            MessageBox(_T("WSAAyncSelect error!"));
    }
    memset(&serverAddress,0,sizeof(sockaddr_in));
    serverAddress.sin_family=AF_INET;
    serverAddress.sin_addr.S_un.S_addr = INADDR_ANY;
    serverAddress.sin_port = htons(6666);

    if(bind(serverSocket,(sockaddr*)&serverAddress,sizeof(serverAddress))==SOCKET_ERROR){
        MessageBox(_T("套接字绑定到端口失败!"));
        return false;
    }
    if (listen(serverSocket, 10)==SOCKET_ERROR)
    {
        MessageBox(_T("监听失败!"));
        return false;
    }
    int len = sizeof(serverAddress);
    //if((sAccept==accept(serverSocket, (sockaddr *)&serverAddress, &len)!=INVALID_SOCKET)) 
    //    MessageBox(_T("success!"));
    return true;

}


afx_msg LRESULT CChatDlg::OnSocket(WPARAM wParam, LPARAM lParam)
{
 switch(WSAGETSELECTEVENT(lParam))  
        {  
        case FD_ACCEPT://接受客户端连接请求。  
            {  
                int len = sizeof(clientAddr);
                sAccept=accept(serverSocket, (sockaddr *)&clientAddr, &len);
                if(sAccept==INVALID_SOCKET)  
                {
                    MessageBox(_T("accept error!"));
                    break;
                }
                if (WSAAsyncSelect(sAccept, m_hWnd, WM_SOCKET, FD_READ|FD_CLOSE)==SOCKET_ERROR)
                {
                    CString temp;
                    temp.Format(_T("%d"), WSAGetLastError());
                    MessageBox(temp);
                    MessageBox(_T("WSAAyncSelect error!"));
                }
                MessageBox(_T("success!"));
                //在新接受的套接字发生FD_READ,FD_WRITE,FD_CLOSE网络事件发生,发送WM_SOCKET消息;  
            }  
            break;  
        case FD_READ://可读,接收数据。  
            {  
                MessageBox(_T("read!"));
                if (recvData())
                    UpdateData(false);
                
            }  
            break;  
        case FD_CLOSE://对方关闭套接字连接。  
            {  
               closesocket(sAccept);
               WSACleanup(); 
            }  
            break;  
        default:  
            break;  
        }  
    return 0;
}
bool CChatDlg::recvData()
{
    CString temp;
    int recvLen = 0;
    int len = 0;
    while (1)
    {
        len = recv(sAccept, recvBuff+recvLen, 100, 0);
        if (len < 100)
            break;
        recvLen += len;
    }
    WCHAR wch[1000];
    int n = MultiByteToWideChar( //转换Unicode到Ansi 
    936, 
    0, 
    recvBuff, 
    -1, 
    wch, //转换到缓冲区中 
    100000 //最多个字节 
    );
    m_recv += _T("client:\r\n");
    m_recv+=wch;
    return true;
}



void CChatDlg::OnBnClickedButtonSend()
{
    UpdateData(true);
    
    USES_CONVERSION; //定义后才能使用T2A
    sprintf_s(sendBuff,1024,"%s\r\n",T2A(m_send));
    int err = send(sAccept, sendBuff, strlen(sendBuff), 0);
    if (SOCKET_ERROR == err)
    {
        MessageBox(_T("send error!"));
    }
    m_recv+=_T("server:\r\n");
    m_recv+=m_send;
    m_recv+=_T("\r\n");
    m_send = _T("");
    UpdateData(false);
}

WSAAsyncSelect函数在服务器时,要在bind函数之前使用,在客户端在connect函数之前,客户端的不同之处就是就是没有fd_accept这个事件,直接 fd_read事件即可。