注册 登录
电子工程世界-论坛 返回首页 EEWORLD首页 频道 EE大学堂 下载中心 Datasheet 专题
lee198717的个人空间 https://home.eeworld.com.cn/space-uid-103677.html [收藏] [复制] [分享] [RSS]
日志

UDP客户端程序框架

已有 1159 次阅读2013-2-25 11:26 |个人分类:MFC开发总结|

在主对话框类头文件中添加以下对话框成员变量:

 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();
}
评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册

热门文章