2009-07-02 6 views
0

J'ai un problème avec un wrapper UDPSocket que j'ai écrit. J'ai un réseau local à faible latence à bande passante élevée sur lequel j'émets des paquets UDP. Je ne m'inquiète pas trop de la fiabilité de l'arrivée des paquets, mais il est extrêmement important que les paquets qui arrivent arrivent si vite. Voici le code correspondant pour la mise en place d'une prise:Linux vers WinXP sur le décalage UDP

bool UDPSocket::create() { 
    int on = 1; 
#ifdef WIN32 
    if(WSAStartup(MAKEWORD(1,1), &SocketInfo) != 0) { 
     MessageBox(NULL, "Cannot initialize WinSock", "WSAStartup", MB_OK); 
    } 
#endif 
    m_sock = socket(PF_INET, SOCK_DGRAM, 0); 
#ifdef WIN32 
    if(setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) == SOCKET_ERROR) 
     return false; 
#else 
    if(setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) == -1) 
     return false; 
#endif 
    addrLen = sizeof(struct sockaddr); 
    return true; 
} 

bool UDPSocket::bind(const int port) { 
    if(!is_valid()) 
     return false; 
    m_addr.sin_family = AF_INET; 
    m_addr.sin_addr.s_addr = htonl(INADDR_ANY); 
    m_addr.sin_port = htons(port); 

    if(::bind(m_sock, (struct sockaddr*)&m_addr, sizeof(m_addr))<0) { 
     std::cout << "UDPSocket: error on bind" << std::endl; 
     return false; 
    } 
    return true; 
} 
bool UDPSocket::send(const std::string s) const { 
    const char* buf = s.c_str(); 

    ::sendto(m_sock, buf, strlen(buf), 0, (const sockaddr*)&clientAddr, addrLen); 
    return true; 
} 

bool UDPSocket::setDestination(const std::string ip, const int port) { 
    memset(&clientAddr, 0, sizeof(clientAddr)); 

    clientAddr.sin_family = AF_INET; 
    clientAddr.sin_addr.s_addr = inet_addr(ip.c_str()); 
    clientAddr.sin_port = htons(port); 

    return true; 
} 

int UDPSocket::recv(std::string& s) const { 
    char buffer[MAXRECV + 1]; 
    struct timeval tv; 
    fd_set fdset; 
    int rc, nread; 

    memset(&buffer, 0, sizeof(buffer)); 

    FD_ZERO(&fdset); 
    FD_SET(m_sock, &fdset); 

    tv.tv_sec = 0; 
    tv.tv_usec = m_timeout; 

    rc = select(m_sock + 1, &fdset, (fd_set *) 0, (fd_set *) 0, &tv); 

    if(FD_ISSET(m_sock, &fdset)) { 
#ifdef WIN32 
     nread = ::recvfrom(m_sock, buffer, MAXRECV, 0, (sockaddr*)&clientAddr, const_cast< int * __w64 >(&addrLen)); 
#else 
     nread = ::recvfrom(m_sock, buffer, MAXRECV, 0, (sockaddr*)&clientAddr, (socklen_t*)&addrLen); 
#endif 
     if(nread < 0) { 
      return -1; 
     } else if(nread == 0) { 
      return 0; 
     } 
     s = std::string(buffer); 
     return nread; 
    } else { 
     return 0; 
    } 
} 
void UDPSocket::set_non_blocking(const bool b) { 
    mNonBlocking = b; 
#ifdef WIN32 
    u_long argp = b ? 1 : 0; 
    ioctlsocket(m_sock, FIONBIO, &argp); 
#else 
    int opts = fcntl(m_sock, F_GETFL); 
    if(opts < 0) return; 
    if(b) 
     opts |= O_NONBLOCK; 
    else 
     opts &= ~O_NONBLOCK; 

    fcntl(m_sock, F_SETFL, opts); 
#endif 
} 

Mon code d'utilisateur, sur les deux extrémités, créez un « envoi » et « recevoir » UDPSocket et les lier à leurs ports respectifs, utiliser ensuite envoyer() pour envoyer données et recv() à recevoir. D'une part, le côté linux semble recevoir pratiquement immédiatement, mais le côté Windows a un retard jusqu'à 1 seconde avant de recevoir des données. Cependant, :: recv() ne renvoie jamais 0 à ce moment-là. Est-ce que je manque quelque chose d'évident?

+0

Un gentleman du nom de Mike Simpson qui ne peut pas encore poster de commentaires sur SO rencontre le même problème. Si vous êtes toujours intéressé à trouver celui-ci, pouvez-vous lui envoyer une ligne à [email protected]? S'il te plaît et merci. Si non, pas de mal. –

Répondre

1

avez-vous essayé les quatre combinaisons (linux-> linux, win-> linux, linux-> win, win-> win)? qui ont des retards et qui pas? , Utilisez également un renifleur de paquets (comme tcpdump ou wireshark) pour voir si le délai est avant ou après avoir frappé le fil.

0

Ce n'est pas une réponse directe. Peut être que vous pouvez essayer des outils comme ttcp (http://www.pcausa.com/Utilities/pcattcp.htm), qui peuvent tester les performances TCP et UDP. Et, vous pouvez également vérifier leur code source, qui est dans le domaine public.

0

Si vous avez le temps d'expérimenter, essayez une version IOCP du code.

Je n'ai jamais fait confiance à l'implémentation win select, avec sa limite de 64 bits.