WinSocketTest 2.0

WinSocketTest 2.0
  在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);
}

你可能感兴趣的:(WinSocketTest 2.0)