最近的项目开发中,网络部分的实现采用自定义的通讯协议,为了保证服务器安 全稳定运行,保证数据发送速度(相对于TCP来说),采用UDP协议。 UDP TCP的优劣在此不再重复。
在采用UDP协议时候, 问题也就跟着来了。UDP协议的本质决定了数据包的不可靠传输,我们无法知道数据包何时会被遗失,所以采用UDP传输信息,就必须自己控制和解决丢包、超时、重传问题。这是一个很久以来一直都在讨论的且未得到完美解决的问题。
不多说了,下面看一段程序吧。 这是我在一个线程中实现的代码。
// 转载出处,做人要厚道!
DWORD CALLBACK UDPLogin(void *p)recv函数
{
  fd_set  readfds;
  struct timeval  authtime;
  int retries=0,retry_max=10; //重试10
  char SendBuffer[MAXBUFLEN]; //发送区
  char RecvBuffer[MAXBUFLEN]; //接收区
  int size=sizeof(struct sockaddr);
// 示例发送内容
  strcpy(SendBuffer,username); //用户名
  strcpy(SendBuffer+strlen(username),password); //密码
  // 设置超时时间
  authtime.tv_usec = 0L;
  authtime.tv_sec = (long)1; // 1秒后重发

  while(1)   
  {
    //发送数据
    sendto(m_Socket,SendBuffer,MAXBUFLEN,0, (struct sockaddr *)&remote_addr,sizeof(remote_addr));

    memset(RecvBuffer,0,sizeof(RecvBuffer));
    //下面2 句非常重要,为select 函数做准备
    FD_ZERO (&readfds);//
    FD_SET (m_Socket, &readfds);//

    if(select(m_Socket,&readfds,NULL,NULL,&authtime) < 0)
    {return -1;}
   
    if (FD_ISSET(m_Socket, &readfds)) // 有东西读,就读
    {
      recvfrom(m_Socket,RecvBuffer,MAXBUFLEN,0,(struct sockaddr *)&remote_addr,&size);
      // 读完就可以自己处理一下收到的数据了,省略。。
        break;
    }
    // 如果没东西读,就表示发送失败,或者网络丢包了
    // 那么就记录次数
    if (++retries >= retry_max)
    {
      MessageBox(NULL,"请检查网络设置是否正确。然后重启本软件","登陆失败",MB_OK);
      return -1;
    }
  }//while
  return 0;
}
其实,上面的关键在于select 函数!!
一个FD_ISSET(readfds)就相当通知了readfds可读。
至于struct timeval在此的功能,请查询 select。不同的timeval设置 使使select()表现出超时结束、无超时阻塞和轮询三种特性。由于
timeval可精确至百万分之一秒,所以WindowsSetTimer()根本不算 什么。你可以用select()
做一个超级时钟。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。