在VS下建一个对话框的MFC程序UDPChat,去掉所有带的控件。加入以下控件:
按钮一个   IDC_BTN_SEND
编程框三个 IDC_EDIT_PORT(端口号),IDC_EDIT_REC(显示接收到的消息),IDC_EDIT_SEND(输入发送内容)
IP控件一个 IDC_IPADDRESS1
UDPChatDlg.h中加入
#define    WM_RECDATA WM_USER+1
来定义一个消息号,用来处理接收到消息的事件
然后是以下方法声明:
private:
    bool InitSocket(void);
    static DWORD WINAPI RecProc(LPVOID lpParam);
    afx_msg LRESULT OnRecData(WPARAM wParam,LPARAM lParam);
    afx_msg void OnBnClickedBtnSend();
消息映射里加入两条:
ON_MESSAGE(WM_RECDATA, OnRecData)//处理收到消息事件
ON_BN_CLICKED(IDC_BTN_SEND, &CTcpChatDlg::OnBnClickedBtnSend)//处理按钮点击事件
至此,万事具备,只欠东风。
首先窗口初始化函数OnInitDialog里加入
    //构造一个新线程用于监听接收
    HANDLE hThread = 
        CreateThread(NULL, 0, RecProc, (LPVOID)m_hWnd, 0, NULL);
    CloseHandle(hThread);
    ((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->SetAddress(127, 0, 0, 1);
    SetDlgItemText(IDC_EDIT_PORT, _T("6000"));
后面就是四个相关的成员函数,需要注意的是在线程必须使用静态函数或者全局函数,因为这程序一开始,线程就运行起来了,而成员方法在那个时候可能还没有生成出来。
bool CTcpChatDlg::InitSocket()
{
    WORD wVersionRequested;
    WSADATA wsaData;
    wVersionRequested = MAKEWORD( 2, 2 );
    int err = WSAStartup( wVersionRequested, &wsaData );
    if ( err != 0 ) {
        /* Tell the user that we could not find a usable */
        /* WinSock DLL.                                  */
        return false;
    }
    if ( LOBYTE( wsaData.wVersion ) != 2 ||
        HIBYTE( wsaData.wVersion ) != 2 ) {
            /* Tell the user that we could not find a usable */
            /* WinSock DLL.                                  */
            WSACleanup( );
            return false; 
    }
    return true;
}
DWORD WINAPI CTcpChatDlg::RecProc(LPVOID lpParam)
{
    HWND hWnd = (HWND)lpParam;
    //-----------------------------------------------
    // Create a receiver socket to receive datagrams
    SOCKET RecvSocket = socket(AF_INET, SOCK_DGRAM, 0);
    if(INVALID_SOCKET == RecvSocket)
    {            
        ::AfxMessageBox(_T("socket创建失败"));
        return 1;
    }
    //-----------------------------------------------
    // Bind the socket to any address and the specified port.
    SOCKADDR_IN RecvAddr;
    RecvAddr.sin_family = AF_INET;
    RecvAddr.sin_port = htons(6000);
    RecvAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    if(SOCKET_ERROR == bind(RecvSocket, (SOCKADDR *) &RecvAddr, sizeof(RecvAddr)))
    {
        closesocket(RecvSocket);
        ::AfxMessageBox(_T("bind失败"));
        return 1;
    }
    //-----------------------------------------------
    // Call the recvfrom function to receive datagrams
    // on the bound socket.
    int retval;
    char RecvBuf[1024];
    char tmpBuf[1024];
    sockaddr_in SenderAddr;
    int SenderAddrSize = sizeof(SenderAddr);
    while(true)
    {
        retval = recvfrom(RecvSocket, 
            RecvBuf, 
            1024, 
            0, 
            (SOCKADDR *)&SenderAddr, 
            &SenderAddrSize);
        if(SOCKET_ERROR == retval)
        {
            CString strError;
            strError.Format("error code : %d", WSAGetLastError());
            ::AfxMessageBox(strError);
            break;
        }
        sprintf_s(tmpBuf, 1024, "收到%s消息: %s", inet_ntoa(SenderAddr.sin_addr), RecvBuf);
        //发送消息
        ::PostMessage(hWnd, WM_RECDATA, 0, (LPARAM)tmpBuf);
    }
    //清理工作
    closesocket(RecvSocket);
    WSACleanup();
    return 0;//成功
}
LRESULT CTcpChatDlg::OnRecData(WPARAM wParam,LPARAM lParam)
{
    CString str((char*)lParam);
    CString origin;
    GetDlgItemText(IDC_EDIT_REC,origin);
    str += "\r\n";
    str += origin;
    SetDlgItemText(IDC_EDIT_REC,str);
    SetDlgItemText(IDC_EDIT_SEND, _T(""));
    return 0;
}
void CTcpChatDlg::OnBnClickedBtnSend()
{
    DWORD dwIP;
    ((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP);
    CString strPort;
    GetDlgItemText(IDC_EDIT_PORT, strPort);
    //创建发送地址信息
    SOCKADDR_IN addrTo;
    addrTo.sin_family = AF_INET;
    addrTo.sin_port = htons(atoi(strPort));
    addrTo.sin_addr.S_un.S_addr = htonl(dwIP);
    CString strMsg;
    GetDlgItemText(IDC_EDIT_SEND, strMsg);
    SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
    if(SOCKET_ERROR == 
        sendto(
        sock, strMsg, 
        strMsg.GetLength()+1, 0, 
        (SOCKADDR *)&addrTo, sizeof(addrTo)
        ))
    {
        CString strError;
        strError.FormatMessage("Send Failed, Error Code: %d", WSAGetLastError());
        MessageBox(strError);
    }
    
    closesocket(sock);
}