Dois-je lier un socket UDP dans mon programme client pour recevoir des données? (J'ai toujours WSAEINVAL)
Je suis entrain de créer un socket UDP (AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
) via Winsock et d'essayer de recvfrom
sur cette prise, mais il renvoie toujours -1 et j'ai WSAEINVAL (10022). Pourquoi?
Quand je bind()
le port, qui n'arrivera pas, mais j'ai lu que c'est très mesquin de lier le client socket.
Je suis l'envoi de données sur mon serveur, qui répond, ou au moins, essaie de.
Inc::STATS CConnection::_RecvData(sockaddr* addr, std::string &strData)
{
int ret; //return code
int len; //length of the data
int fromlen; //sizeof(sockaddr)
char *buffer; //will hold the data
char c;
//recv length of the message
fromlen = sizeof(sockaddr);
ret = recvfrom(m_InSock, &c, 1, 0, addr, &fromlen);
if(ret != 1)
{
#ifdef __MYDEBUG__
std::stringstream ss;
ss << WSAGetLastError();
MessageBox(NULL, ss.str().c_str(), "", MB_ICONERROR | MB_OK);
#endif
return Inc::ERECV;
}
...
C'est un exemple que j'ai écrit il y a quelques instants, et il fonctionne sans l'appel à bind()
dans le client:
#pragma comment(lib, "Ws2_32.lib")
#define WIN32_LEAN_AND_MEAN
#include <WS2tcpip.h>
#include <Windows.h>
#include <iostream>
using namespace std;
int main()
{
SOCKET sock;
addrinfo* pAddr;
addrinfo hints;
sockaddr sAddr;
int fromlen;
const char czPort[] = "12345";
const char czAddy[] = "some ip";
WSADATA wsa;
unsigned short usWSAVersion = MAKEWORD(2,2);
char Buffer[22] = "TESTTESTTESTTESTTEST5";
int ret;
//Start WSA
WSAStartup(usWSAVersion, &wsa);
//Create Socket
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
//Resolve host address
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_protocol = IPPROTO_UDP;
hints.ai_socktype = SOCK_DGRAM;
if(getaddrinfo(czAddy, czPort, &hints, &pAddr))
{
std::cerr << "Could not resolve address...\n";
std::cin.get();
return 1;
}
//Start Transmission
while(1)
{
ret = sendto(sock, Buffer, sizeof(Buffer), 0, pAddr->ai_addr,
pAddr->ai_addrlen);
if(ret != sizeof(Buffer))
{
std::cerr << "Could not send data\n";
std::cin.get();
return 1;
}
fromlen = sizeof(SOCKADDR);
ret = recvfrom(sock, Buffer, sizeof(Buffer), 0, &sAddr, &fromlen);
if(ret != sizeof(Buffer))
{
std::cout << "Could not receive data - error: " <<
WSAGetLastError() << std::endl;
std::cin.get();
return 1;
}
Buffer[ret-1] = '\0';
std::cout << "Received: " << Buffer << std::endl;
}
return 0;
}
Vous devez vous connecter pour publier un commentaire.
Avec UDP, vous devez
bind()
la prise du client UDP est sans connexion, donc il n'y a pas d'autre voie pour la pile à savoir quel est le programme de livrer des datagrammes pour un port particulier.Si vous pouviez
recvfrom()
sansbind()
, vous pensez peut-être demander à la pile pour donner à votre programme tous les datagrammes UDP envoyés à l'ordinateur. Depuis la pile fournit des datagrammes à un seul programme, ce serait briser DNS, Windows Voisinage Réseau, réseau de synchronisation de l'heure....Vous avez pu le lire quelque part sur le net que la liaison à un client est boiteux, mais ce conseil ne s'applique qu'aux connexions TCP.
Votre autre exemple de code fonctionne parce que vous êtes à l'aide de
sendto
avantrecvfrom
. Si un socket UDP est indépendant et soitsendto
ouconnect
sont appelés sur elle, le système va automatiquement une liaison pour vous et ainsi, lerecvfrom
appeler plus tard sur réussira.recvfrom
ne va pas se lier à une socket, que cet appel s'attend à ce que le socket avoir été relié déjà, ou une erreur sera levée.J'ai eu le même problème il y a quelques semaines, les remarques suivantes m'ont aidé à comprendre si l'explicite appel de bind() est nécessaire:
la fonction recvfrom (MSDN)
sendto fonction (MSDN)
Ici il est dit ce qui suit:
Paramètres
s [en]: Un descripteur de l'identification d'un bond socket.
...
Valeur De Retour
WSAEINVAL: La prise n'a pas été lié avec bind, ou un inconnu drapeau a été spécifié, ou drapeaux msg_oob a été spécifié pour un socket avec SO_OOBINLINE activé, ou (pour les flux d'octets de style sockets seulement) len était nul ou négatif.
Aussi loin que je me souviens de lier n'est pas nécessaire pour un socket UDP, car un appel de liaison est fait pour vous, par la pile. Je suppose que c'est un Windows chose à exiger un bind sur un socket utilisé dans un recvfrom appel.