VC++6.0使用select出现10022错误的解决办法

//加载winsock库
if (WSAStartup(MAKEWORD(2,2),&wsadata)!=0)
{
   int error1 = WSAGetLastError();
  
   CString error_str1;
   error_str1.Format("%d",error1);

   error_str1 = "加载winsock库失败,错误代码:"+error_str1;
  
AfxMessageBox(error_str1);
  
   return 1;
}

connectsock = socket(AF_INET,SOCK_STREAM,0);//创建套接字

if (connectsock==INVALID_SOCKET)
{
   int error2 = WSAGetLastError();
  
   CString error_str2;
   error_str2.Format("%d",error2);
  
   error_str2 = "套接字创建失败,错误代码:"+error_str2;
  
   AfxMessageBox(error_str2);

   return 1;
  
}

sockaddr_in ser;
ser.sin_family = AF_INET;
ser.sin_port = htons(5001);
ser.sin_addr.s_addr = inet_addr(netipstr);

//请求与服务器建立连接
if(connect(connectsock,(struct sockaddr*)&ser,sizeof(ser))==SOCKET_ERROR){
  
   int error3 = WSAGetLastError();
  
   CString error_str3;
   error_str3.Format("%d",error3);
  
   error_str3 = "连接对方主机失败,错误代码:"+error_str3;

   AfxMessageBox(error_str3);
  
   return 1;
  
}

memset(recvbuf,0,sizeof(recvbuf));

FD_ZERO(&fdread);

FD_SET(connectsock,&fdread);

tv.tv_sec = 1;//设置延迟为1秒

tv.tv_usec = 0;

while(1){
    
   int iselect = select(0,&fdread,NULL,NULL,&tv);

   if(iselect<0){

    int error4 = WSAGetLastError();

    CString error_str4;
   
    error_str4.Format("%d",error4);
  
    error_str4 = "select发生错误,错误代码:"+error_str4;

AfxMessageBox(error_str4);

    return 1;
   }

   if(FD_ISSET(connectsock,&fdread)){//检查套接字connectsock是否在结合fdread中,即检查是否有数据到来
   

    memset(recvbuf,0,sizeof(recvbuf));

    lenrecv = recv(connectsock,recvbuf,sizeof(recvbuf),0);
   

   //数据处理省略

}else{//数据未到

//数据处理省略

}

}

这个程序,已经把妨碍分析的程序略去,经过测试,第一次select检查的时候没有报错,而第二次检查的时候就报了10022错误,那出错的原因是什么呢?我先来解释一下select函数的作用。

select函数:如果程序要检查套接字上是否有数据到来,则首先需要把套接字句柄加入可读性监视集合中,然后调用select,如果该套接字没有数据需要接收,则select函数会把该套接字从可读性监视集合中删除,所以,程序只要检查该套接字句柄是否还在可读性监视集合中,就可以判断出是否有数据需要接收。

这下我们明白了为什么了吧,原因就是因为我们第一次调用select函数的时候,没有数据到来,select函数将套接字从可读性监视集合中删除,而我们第二次调用select函数的时候,系统认为你提供了非法参数,所以会报10022错误。

解决办法就是在每次调用select之前必须加入如下代码:

FD_ZERO(&fdread);

FD_SET(connectsock,&fdread);

tv.tv_sec = 1;//设置延迟为1秒

tv.tv_usec = 0;

修改后的程序:

//加载winsock库
if (WSAStartup(MAKEWORD(2,2),&wsadata)!=0)
{
   int error1 = WSAGetLastError();
  
   CString error_str1;
   error_str1.Format("%d",error1);

   error_str1 = "加载winsock库失败,错误代码:"+error_str1;
  
AfxMessageBox(error_str1);
  
   return 1;
}

connectsock = socket(AF_INET,SOCK_STREAM,0);//创建套接字

if (connectsock==INVALID_SOCKET)
{
   int error2 = WSAGetLastError();
  
   CString error_str2;
   error_str2.Format("%d",error2);
  
   error_str2 = "套接字创建失败,错误代码:"+error_str2;
  
   AfxMessageBox(error_str2);

   return 1;
  
}

sockaddr_in ser;
ser.sin_family = AF_INET;
ser.sin_port = htons(5001);
ser.sin_addr.s_addr = inet_addr(netipstr);

//请求与服务器建立连接
if(connect(connectsock,(struct sockaddr*)&ser,sizeof(ser))==SOCKET_ERROR){
  
   int error3 = WSAGetLastError();
  
   CString error_str3;
   error_str3.Format("%d",error3);
  
   error_str3 = "连接对方主机失败,错误代码:"+error_str3;

   AfxMessageBox(error_str3);
  
   return 1;
  
}

memset(recvbuf,0,sizeof(recvbuf));

while(1){

   FD_ZERO(&fdread);

   FD_SET(connectsock,&fdread);

   tv.tv_sec = 1;//设置延迟为1秒

   tv.tv_usec = 0;
    
   int iselect = select(0,&fdread,NULL,NULL,&tv);

   if(iselect<0){

    int error4 = WSAGetLastError();

    CString error_str4;
   
    error_str4.Format("%d",error4);
  
    error_str4 = "select发生错误,错误代码:"+error_str4;

AfxMessageBox(error_str4);

    return 1;
   }

   if(FD_ISSET(connectsock,&fdread)){//检查套接字connectsock是否在结合fdread中,即检查是否有数据到来
       memset(recvbuf,0,sizeof(recvbuf));

    lenrecv = recv(connectsock,recvbuf,sizeof(recvbuf),0);
   //数据处理省略

}else{//数据未到

//数据处理省略

}

}

作者: fireaxe   发布时间: 2010-09-24