写一个查看远端主机上文件列表的程序,A取B的文件列表时,B循环调用Send函数每次发送一个文件名。一般没有问题,但当文件数较多时(比如c:\windows\system32目录下,有两千多文件和文件夹),就会出现错误void Send(char *strIP, int nPort)
{
         if((*strIP <= '9') && (*strIP >= '0'))
{
if((ip = inet_addr(strIP)) == INADDR_NONE)
{
AfxMessageBox("bad ip."); //这里有时出错,我下断点看到出错时strIP =127.0.0.1,是正
return FALSE;             //确的,但就是会走到这里
}
}
 //......
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(nPort);
addr.sin_addr = *(in_addr*)&ip;

m_hSock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if ( m_hSock == INVALID_SOCKET)
{
AfxMessageBox("invalid socket");
int nErr = WSAGetLastError();
return FALSE;
}
int nRet;
nRet = connect(m_hSock,(sockaddr*)&addr,sizeof(sockaddr));
if ( nRet == SOCKET_ERROR )
{
int nErr = WSAGetLastError();
AfxMessageBox("connect err"); //这里错的几率较大,错误号10060
return FALSE;
}
//...
         closesocket(m_hSock);
接收数据部分代码Listen()
{
m_hSockL = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_hSockL == SOCKET_ERROR)//这里面查错的代码都省略了
{      
return false;
}
sockaddr_in local;
local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
local.sin_family = AF_INET;
local.sin_port = htons(8000);

if (bind(m_hSockL, (sockaddr*)&local, sizeof(local)) == SOCKET_ERROR)
{
return false;
} if (listen(m_hSockL, SOMAXCONN) == SOCKET_ERROR)
{
return false;
}

HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)AcceptThread, (LPVOID)this, 0, NULL);
CloseHandle(hThread);
return true;
}
DWORD WINAPI AcceptThread(LPVOID lParam)
{        //...
SOCKET sRecv;
while(1)
{
sockaddr_in client;
int iAddrSize = sizeof(client);
sRecv  = accept(pClass->m_hSockL,(sockaddr*)&client, &iAddrSize);
if( sRecv == INVALID_SOCKET)
{
char szErr[256] = {0};
sprintf(szErr, "accept failed:%d", WSAGetLastError());
return 0;
}
           //...
HANDLE hThread = CreateThread(NULL, 0, 
                                         (LPTHREAD_START_ROUTINE)RecvThread, (LPVOID)sRecv, 0, NULL);
CloseHandle(hThread);
}
return 0;}
DWORD WINAPI RecvThread(LPVOID lParam)
{
char szBuf[BUFLEN] = {0};
int nRet = 0,nCount = 0,nTime = 1000*5; //nTime是超时值
SOCKET sock = (SOCKET)lParam;
do
{
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&nTime, sizeof(nTime)); //设置超时
nRet = recv(sock, szBuf+nCount, BUFLEN-nCount, 0);
nCount += nRet;
}while( (nRet>0) && (nCount<BUFLEN) );
         //...
         closesocket(sock);
         return 0;
}我之前用了一下WSAAsyncSelect,但是发送速度快了会有FD_READ消息收不到的情况,加了确认重传包是不丢了,但是效率却低了很多,所以改回同步的,现在又遇到这个问题。怎么样能让传输速度尽可能的快,而且不出现丢包之类的错误呢?

解决方案 »

  1.   

     addr.sin_addr = *(in_addr*)&ip;这个ip是什么类型?任何时候都应该避免使用127.0.0.1为地址(当然你的错误应该和它没有关系),你在inet_addr错误之后需要GetLastError得到错误码,否则别人不可能知道怎么拉
      

  2.   

    回复2L:
    ip是unsigned long类型的。
    关于inet_addr这个函数,MSDN里没有说明它出错可以用WSAGetlasterror之类的函数取错误码,我试了WSAGetlasterror和GetLastError,返回值都是0。
    单步调试的时候,在connect那里有时会返回10049错误号。
      

  3.   

    你需要发送到不同的IP吗?
    你的connect像阻塞模式,返回失败10062,就说明对方拒绝连接哦
      

  4.   

    addr.sin_addr = *(in_addr*)&ip;
    改成
    addr.s_addr = htonl(ip);
    不是什么都可以强制类型转换的
      

  5.   


    nRet = connect(m_hSock,(sockaddr*)&addr,sizeof(sockaddr));
        if ( nRet == SOCKET_ERROR )
        {
            int nErr = WSAGetLastError();
            AfxMessageBox("connect err"); //这里错的几率较大,错误号10060
            return FALSE;
        }
    //...
             closesocket(m_hSock);”你是每send一个文件就要connect一次吗?
    如果是这样的话,很有可能你closesocket时,socket还未真正的关闭,而这时你又connect,所以会导致出错。
    建议你可以

    BOOL bDontLinger = FALSE;
      setsockopt( s, SOL_SOCKET, SO_DONTLINGER, ( const char* )&bDontLinger, sizeof( BOOL ) );
    ”在调用closesocket()后强制关闭,不经历TIME_WAIT的过程。但是这样有个问题就是,会send还未完成,就close了。
    所以也不太建议这样做。
    但是可以这样做。

    struct linger {
      u_short l_onoff;
      u_short l_linger;
      };
      linger m_sLinger;
      m_sLinger.l_onoff = 1; //在调用closesocket()时还有数据未发送完,允许等待
      // 若m_sLinger.l_onoff=0;则调用closesocket()后强制关闭
      m_sLinger.l_linger = 5; //设置等待时间为5秒
      setsockopt( s, SOL_SOCKET, SO_LINGER, ( const char* )&m_sLinger, sizeof( linger ) );”
    可以将“m_sLinger.l_linger = 5; ”设置下时间,或者“m_sLinger.l_linger = 0;表示等待的时间为无穷大,即直到send完成为止。 ”
      

  6.   

    谢谢大家的帮助,我已经重写了,采用一次connect多次send的方式。重写后connect出错的概率的确小了很多。