Udp Select

来源:互联网 发布:淘宝怎样打印电子面单 编辑:程序博客网 时间:2024/05/16 15:08

最近的项目开发中,网络部分的实现采用自定义的通讯协议,为了保证服务器安 全稳定运行,保证数据发送速度(相对于TCP来说),采用UDP协议。 UDP 和 TCP的优劣在此不再重复。
在采用UDP协议时候, 问题也就跟着来了。UDP协议的本质决定了数据包的不可靠传输,我们无法知道数据包何时会被遗失,所以采用UDP传输信息,就必须自己控制和解决丢包、超时、重传问题。这是一个很久以来一直都在讨论的且未得到完美解决的问题。
不多说了,下面看一段程序吧。 这是我在一个线程中实现的代码。

// 转载出处,做人要厚道!

DWORD CALLBACK UDPLogin(void *p)
{
  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, (structsockaddr *)&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,(structsockaddr *)&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()做一个超级时钟。

原创粉丝点击