xilebo noone | J'en profite pour poser une 2ème question : l'UDP unicast ne fonctionne pas sous linux alors que le même code fonctionne sous windows.
A priori , c'est l'appel à la fonction connect qui fait échouer.
Voici les portions de code ( dialogue entre 2 machines : 172.17.0.163 le test unitaire sous linux , 172.17.0.160 le serveur qui réceptionne le test sous windows )
Initialisation de la socket
Code :
- int oui = 1;
- m_socket = socket( AF_INET , SOCK_DGRAM , IPPROTO_UDP );
- if ( m_socket >= 0)
- {
- // options de socket devant être paramétrées *avant* le bind() ou connect()
- #ifdef SO_NOSIGPIPE
- if (setsockopt( m_socket , SOL_SOCKET, SO_NOSIGPIPE, (char *)&oui, sizeof(oui)) < 0)
- {
- ERROR(("setsockopt(SO_NOSIGPIPE): %s", strerror_socket(errno)));
- CloseSocket( );
- return PRT_FAILED;
- }
- #endif
- if (setsockopt( m_socket , SOL_SOCKET, SO_REUSEADDR, (char *)&oui, sizeof(oui)) < 0)
- {
- ERROR((setsockopt(SO_REUSEADDR): %s", strerror_socket(errno)));
- CloseSocket( );
- return PRT_FAILED;
- }
- #ifdef SO_REUSEPORT
- if (setsockopt( m_socket , SOL_SOCKET, SO_REUSEPORT, (char *)&oui, sizeof(oui)) < 0)
- {
- ERROR(("setsockopt(SO_REUSEPORT): %s", strerror_socket(errno)));
- CloseSocket( );
- return PRT_FAILED;
- }
- #endif
- ULONG hote_l =INADDR_NONE;
- hote_l = inet_addr( m_address_sz );
- ULONG peer_l;
- peer_l = inet_addr( m_pair_address_sz );
- if ( hote_l == INADDR_NONE )
- {
- ERROR(("%s is not a valid IP address", m_address_sz ) );
- CloseSocket( );
- return PRT_FAILED;
- }
- struct sockaddr_in adresse;
- memset ( &adresse , 0 , sizeof( adresse ) );
- adresse.sin_family = AF_INET;
- adresse.sin_addr.s_addr = hote_l;
- adresse.sin_port = htons ( (USHORT)m_port_l ); // port stocké dans un long, mais < 65535 donc cast OK
- struct sockaddr_in adresse_peer;
- memset ( &adresse_peer , 0 , sizeof( adresse_peer ) );
- adresse_peer.sin_family = AF_INET;
- adresse_peer.sin_addr.s_addr = peer_l;
- adresse_peer.sin_port = htons( (USHORT)m_port_l); // port stocké dans un long, mais < 65535 donc cast OK
- // boucler les tentatives ?
- if ( bind( m_socket , (struct sockaddr *) &adresse , sizeof (adresse ) ) != 0 )
- {
- ERROR(("bind failed %s", strerror_socket(errno) ) );
- CloseSocket( );
- return PRT_FAILED;
- }
- if ( connect( m_socket , (struct sockaddr *) &adresse_peer , sizeof (adresse_peer ) ) != 0 )
- {
- ERROR(("connect failed %s", strerror_socket(errno) ) );
- CloseSocket( );
- return PRT_FAILED;
- }
- // options de socket devant être paramétrées *apres* le bind() ou connect()
- struct timeval timeout;
- timeout.tv_sec = 0;
- timeout.tv_usec = 100000;
- if (setsockopt( m_socket , SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0)
- {
- PGAS_ERROR(("setsockopt(SO_RCVTIMEO): %s", strerror_socket(errno)));
- CloseSocket( );
- return PRT_FAILED;
- }
- // connection is OK
- m_connected_b = TRUE;
- return PRT_SUCCESS;
- }
- return PRT_FAILED;
|
code faisant le send : Pas besoin de sendto, l'adresse par défaut est celle spécifiée dans le connect
Code :
- while (tot < nBufferSize)
- {
- int envoye = 0;
- envoye = send( m_socket, retour + tot, nBufferSize - tot, 0 );
- if ( envoye < 0)
- {
- ERROR(("erreur d'envoi a %s/%d: %s", m_address_sz, m_port_l, strerror_socket(errno)));
- return PRT_FAILED;
- }
- else
- {
- tot += envoye;
- }
- }
|
code du receive :
Code :
- fd_set fdin;
- timeval tv;
- FD_ZERO(&fdin);
- FD_SET(m_socket, &fdin);
- tv.tv_sec = _timeout / 1000 ;
- tv.tv_usec = ( _timeout % 1000 ) * 1000 ;
- data = select(((int)m_socket)+1, &fdin, NULL, NULL, &tv);
- if (data == -1)
- {
- ERROR(("Erreur select : %s",strerror_socket(errno)));
- return PRT_FAILED;
- }
- else if (FD_ISSET(m_socket, &fdin) != 0)
- {
- recu = recv(m_socket, entete, BUFFERSIZE, 0 );
- }
|
Alors , avec ce code ( qui est le même sur les 2 machines ) voici comment sont fait les appels :
Sur la machine "test unitaire" je fais Init , puis Send, puis Recv , puis Shut.
Sur la machine "serveur pour test" , je fais Init , puis Recv , puis Send, puis Shut Jusque là, c'est normal.
Avec ce code, si les 2 machines sont sous windows, mon test passe.
Avec ce même code, si la machine "test unitaire" est sous linux , et la machine "serveur pour test", le test ne passe pas.
Où est l'échec ? - l'init fonctionne bien des 2 cotés ( les appels systèmes retournent tous OK ).
- le premier envoi sous linux se passe bien car il est bien recu sous windows. L'appel connect sous linux est donc cohérent puisque pour l'envoi, je fais un send, sans préciser le destinaire.
- suite à la réception sous windows, celui-ci envoie une réponse pour être réceptionné sous linux.
- c'est la réception sous linux qui pose problème, le select retourne "nodata", par conséquent, je ne peux pas faire le recv.
- A savoir que si je mets ( juste coté linux ) en commentaire l'appel à connect ( ce qui a pour conséquence de m'obliger à remplacer le send par un sendto vers ma machine "serveur pour test" , je ne change pas le recv , qui revient à faire un recvfrom avec sockaddr_in NULL ) , cela fonctionne bien.
Je ne comprends pas quelle erreur j'ai pu faire qui fait que le comportement est différent sous linux.
Il y a soit un appel de trop qui gêne ( dans les setsockopt par exemple ), soit il manque quelque chose spécifique à linux.
Avez vous une idée car je sèche ?
Merci |