在主对话框类头文件中添加以下对话框成员变量:
SOCKET m_SockClient; //UDP客户端套接字
SOCKADDR_IN m_Serveraddr; //指向服务器的IP地址与端口
添加Winsock版本检测函数:
int CUDP_ClientDlg::CheckWinsockVersion()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2,2);
err = WSAStartup(wVersionRequested,&wsaData);
if (err != 0)
return err;
if ((LOBYTE(wsaData.wVersion) != 2)&& (HIBYTE(wsaData.wVersion) != 2))
{
WSACleanup();
err = WSAVERNOTSUPPORTED;
return err;
}
return err;
}
在对话框类实现文件中添加winsock的配置函数(这里与服务器端不同,客户端不需要bind本机IP和端口,所以在设置修改时直接重新调用本函数对socket进行配置就好,并不需要关闭socket;所以这里函数命名为Reset而不是Init):
void CUDP_ClientDlg::OnBUTTONReset()
{
// TODO: Add your control notification handler code here
if (CheckWinsockVersion()==0)
{
if (m_SockClient != INVALID_SOCKET)
{
closesocket(m_SockClient);
}
//创建客户端Socket
m_SockClient = socket(AF_INET,SOCK_DGRAM,0);
if (m_SockClient==INVALID_SOCKET)
{
AfxMessageBox("创建套接字失败!");
return;
}
UpdateData(TRUE);
DWORD dwIP;
CString strIP;
m_IPADDRESSctr_server.GetAddress(dwIP);
strIP.Format("%d.%d.%d.%d",(0xFF000000&dwIP)>>24,(0xFF0000&dwIP)>>16,(0xFF00&dwIP)>>8,0xFF&dwIP);
//m_Serveraddr.sin_addr.S_un.S_addr = inet_addr((const char *)m_edit_serverIP);
//配置服务器端IP和接口
m_Serveraddr.sin_addr.S_un.S_addr = inet_addr(strIP);
m_Serveraddr.sin_family = AF_INET;
m_Serveraddr.sin_port = htons((u_short)m_edit_port);
//m_Serveraddr.sin_port = htons(60000);
m_initFile.SetFileName(".\\系统配置","客户端UDP配置.ini");//指向exe文件所在的文件夹,文件不存在则会创建
m_initFile.SetString("客户端UDP配置", "服务器IP", strIP);
m_initFile.SetInt("客户端UDP配置", "通信端口", m_edit_port);
if(WSAAsyncSelect(m_SockClient,this->m_hWnd,WM_SOCK_MSG,FD_READ)==SOCKET_ERROR)
AfxMessageBox("注册网络事件失败!");
}
}
注册并编写回调函数用于接收UDP数据:
对话框头文件中添加:
#define WM_SOCK_MSG WM_USER+1 // 用户自定义消息声明
//{{AFX_MSG(CUDP_ClientDlg)
...
afx_msg LRESULT OnSocketMsg(WPARAM wParam,LPARAM lParam); // 注册网络事件消息
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
对话框实现文件中添加:
BEGIN_MESSAGE_MAP(CUDP_ClientDlg, CDialog)
//{{AFX_MSG_MAP(CUDP_ClientDlg)
...
ON_MESSAGE(WM_SOCK_MSG,OnSocketMsg) // 添加网络事件消息响应回调函数
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
回调函数中对接收缓冲区进行处理:
char rxdBuffer[1024]; // 接收缓冲区,直接定义在对话框类实现文件开头,作为全局变量
LRESULT CUDP_ClientDlg::OnSocketMsg(WPARAM wParam, LPARAM lParam)
{
//检索网络事件
switch(WSAGETSELECTEVENT(lParam))
{
case FD_READ:
UpdateData(TRUE);
int size = sizeof(sockaddr_in);
int len = recvfrom(m_SockClient, rxdBuffer, 1024, 0, (struct sockaddr *)&m_Serveraddr, &size); //缓冲区大小为1024字节,见ReceiveBuf的定义
m_edit_rxd += (LPCTSTR)rxdBuffer;//显示接收到的数据包,这里可以加入数据包解析代码
m_edit_rxd += "\r\n";
UpdateData(FALSE);
break;
}
return TRUE;}
UDP数据发送测试:
void CUDP_ClientDlg::OnButtonSend()
{
// TODO: Add your control notification handler code here
if (m_SockClient != INVALID_SOCKET)
{
UpdateData(TRUE);
sendto(m_SockClient,m_edit_txd,m_edit_txd.GetLength()+1,0,(SOCKADDR *)&m_Serveraddr,sizeof(SOCKADDR));
}
else
{
AfxMessageBox("请先配置服务器信息!");
}}
程序退出时收尾工作:
void CUDP_ClientDlg::OnDestroy()
{
CDialog::OnDestroy();
// TODO: Add your message handler code here
closesocket(m_SockServer);
WSACleanup();
}