[win32] UDP netwerk perikelen

Pagina: 1
Acties:

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

Topicstarter
Ja ja, altijd fijn als iets niet werkt zoals het volgens de documentatie zou moeten

Voor netwerkfunctionaliteit in een spel maak ik gebruik van UDP sockets. UDP is een message based protocol (itt TCP wat stream based is), en dus is er geen fysieke connectie. Als je een packet stuurt gaat het gewoon de wijde wereld in, of de andere kant nu luisterd of niet. Ten minste, dit zou vziw de bedoeling moeten zijn.

Wat is het probleem nu? Ik heb een lees-thread die wacht op een event dat aangeeft of er data binnen is. Die event wordt geselecteerd met WSAEventSelect (sock, event, FD_READ). Ik wacht erop met WaitForMultipleObjects (). Dit gaat allemaal heel leuk en aardig, maar als ik de client afsluit zonder netjes een berichtje te sturen dat hij stopt, en ik stuur een berichtje van de server naar de client (die dus dan niet meer luistert), dan wordt de event getriggered aan de server kant. De socket zegt vervolgens dat er 1 byte in de leesbuffer staat. Als ik die probeer uit te lezen dan krijg ik een SOCKET_ERROR met als errorcode WSACONNRESET.

Imho zou dat helemaal niet moeten gebeuren, het is tenslotte een connectionless socket. Hoe weet de serverkant dan in hemelsnaam dat de client z'n socket gesloten heeft? Ik heb met een packetsniffer gekeken, en er komt geen pakketje terug van de client. Hoe kan de server dat dan in hemelsnaam weten :?

Ik heb geprobeerd ook de event te laten triggeren op FD_CLOSE, maar dat gebeurt verder niet (zoals ook zou moeten). Maar ik vind het gewoon wazig dat er 1 byte in de leesbuffer komt te staan zodra je een sendto () doet, die je niet eens uit kan lezen omdat je dan een error terug krijgt.

Ik heb het nu opgelost door op die error te checken, maar toch vind ik het wazig. Is dit normaal?

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • kvdveer
  • Registratie: November 2000
  • Laatst online: 06-11-2025

kvdveer

Z.O.Z.

Disclaimer: hoog [blaat]-gehalte

Is UDP wel volledig connectionless? Het is niet blind in ieder geval. Als een onzin-pakketje binnenkomt (een TCP zonder connectie, of UDP zonder luisteraar) dan wordt een RST-pakketje teruggestuurd. Dit is om achtergrondruis te verminderen.
Volgens mij wordt een UDP-verbinding ook gewoon tot stand gebracht via een SYN-SYN/ACK-ACK handshake, om zo bidirectioneel verkeer mogelijk te maken. Dat vervolgens de pakketjes in die verbinding geen sequence-number meekrijgen is iets anders.
But - i could be wrong.

[ Voor 4% gewijzigd door kvdveer op 01-05-2003 16:46 ]

Localhost, sweet localhost


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

Topicstarter
Nee, er is geen handshake, en ook geen connectie. Dat er een RST pakketje terug wordt gestuurd zou op zich nog kunnen, maar volgens mij hoort dat niet zo te zijn. Ik zie iig ook geen terugkomend pakketje in de packet sniffer (maar ik filterde de pakketjes ook alleen op UDP poort 5000, misschien doet een onderliggende laag iets?)

Er is ook niet zoiets als een 'udp verbinding'. Een host stuurt een pakketje richting een andere host, maar heeft er verder geen weet van of die nou is aangekomen of niet. Als er aan de andere kant een host luistert doet ie er wat mee, en kan ie vervolgens data terug sturen (door het source adres en de poort uit het ontvangen pakketje te halen). Er wordt dus geen verbinding opgezet zoals bij TCP

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • kvdveer
  • Registratie: November 2000
  • Laatst online: 06-11-2025

kvdveer

Z.O.Z.

.oisyn schreef op 01 May 2003 @ 15:52:
Er is ook niet zoiets als een 'udp verbinding'. Een host stuurt een pakketje richting een andere host, maar heeft er verder geen weet van of die nou is aangekomen of niet. Als er aan de andere kant een host luistert doet ie er wat mee, en kan ie vervolgens data terug sturen (door het source adres en de poort uit het ontvangen pakketje te halen). Er wordt dus geen verbinding opgezet zoals bij TCP
RST is geen UDP of TCP... Handshake ook niet trouwens.

Localhost, sweet localhost


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

Topicstarter
kvdveer schreef op 01 May 2003 @ 15:59:
RST is geen UDP of TCP... Handshake ook niet trouwens.
weet je toevallig wat dan wel? Dan kan ik mijn packet sniffer zo configureren dat ie die ook doorlaat (alles doorlaten is geen optie, er is teveel ruis op het netwerk)

.edit: Hmmm, voor zover ik kan vinden met google wordt RST nooit in verband gebracht met UDP, alleen met TCP. Wel vond ik hier deze passage:
UDP processing. UDP processing is similar but simpler, since there is no connection state, except in one regard. If host A sends a UDP packet to host B with a source port of and a destination port of , then Bro considers A as having initiated a ``request'' to B, and establishes pseudo-connection state associated with that request. If B subsequently sends a UDP packet to A with a source port of and destination , then Bro considers this packet to reflect a ``reply'' to the request. The handlers (virtual functions) for the UDP payload data can then readily distinguish between requests and replies for the usual case when UDP traffic follows that pattern. The default handlers for UDP requests and replies simply generate udp_request and udp_reply events.
Die laatste regel suggereert dat er dus wel een pakketje wordt teruggestuurd. En dat is dan idd de default handler, aangezien er niets meer luistert op de betreffende poort

[ Voor 66% gewijzigd door .oisyn op 01-05-2003 16:22 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 22-08 01:56
Als een UDP pakket verstuurd naar een port waar geen socket mee verbonden is, wordt doorgaans een ICMP pakketje terug gestuurd ("destination unreachable" of iets dergelijks). Ik weet trouwens niet zeker of dit verplicht is (UDP is tenslotte een onbetrouwbaar protocol). Dit maakt het ook mogelijk om te portscannen op UDP ports (je stuurt er een UDP pakketje heen en als je als antwoord zo'n ICMP pakketje terug krijgt, dan draait er op die poort waarschijnlijk niets).

In je packet filter moet je dus filteren op IP (dan heb je ICMP er ook bij zitteN) of specifiek op ICMP en UDP. Misschien kun je het netwerkverkeer beperken door te filteren op alles wat niet van je test-host komt.
.oisyn schreef op 01 May 2003 @ 16:14:
Wel vond ik hier deze passage:
[...]
Die laatste regel suggereert dat er dus wel een pakketje wordt teruggestuurd. En dat is dan idd de default handler, aangezien er niets meer luistert op de betreffende poort
Dit lijkt me gewoon een stukje uitleg over hoe die library (?) UDP verkeer interpreteert. Op netwerk nivo is er geen onderscheid tussen requests en replies; er zijn alleen pakketjes en die kunnen aankomen of niet. Als het operating system geen socket bij de gespecificeerde port kan vinden, onderneemt 'ie dus idd een standaard actie, maar die is onafhankelijk van of er ooit een socket geweest is.

[ Voor 39% gewijzigd door Soultaker op 01-05-2003 16:31 ]


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Ik denk dat je connectionless verkeerd hebt geinterpreteerd. UDP weet net als ieder ethernet-derived protocol z'n afzender, en kan dus zoals jij citeert pakketjes terugsturen. Dit is 'rudimentair' een connectie, maar voor zover ik weet niet standaard bij UDP. Kan zijn dat WinSock het toevallig doet.

Wat TCP een 'streaming' protocol maakt met echte connecties zijn sequencing (het feit dat alles op volgorde wordt gezet), handshaking (terugmelden dat pakket X binnen is) en checksumming (controleren dat er geen corruptie is opgetreden). TCP geeft ook statusmeldingen zoals 'disconnecting', terwijl je daar idd in principe bij UDP pas achterkomt zodra je iets terug probeert te sturen.

Professionele website nodig?


  • kvdveer
  • Registratie: November 2000
  • Laatst online: 06-11-2025

kvdveer

Z.O.Z.

Bij het doorbladeren van wat RFC's (76*), kom ik tot de conclusie dat UDP inderdaad geen enkele poging onderneemt om te communiceren buiten de door jou verzonden pakketjes. Ik heb het vermoeden dat IP dat wèl voor je doet, maar daarvan kan ik geen bevestiging vinden. (ik lees ook maar oppervlakkig)

Localhost, sweet localhost


  • The End
  • Registratie: Maart 2000
  • Laatst online: 13:32

The End

!Beginning

In de MSDN staat trouwens dit bij de foutmelding 'WSAECONNRESET':
"The virtual circuit was reset by the remote side executing a hard or abortive close. For UPD sockets, the remote host was unable to deliver a previously sent UDP datagram and responded with a "Port Unreachable" ICMP packet. The application should close the socket as it is no longer usable."

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

Topicstarter
Met ICMP vindt ik ook geen terugkomende pakketjes

.edit: The End: Dat staat bij de send () en sendto () functies, maar daar krijg ik geen error. Die error krijg ik juist bij recvfrom () (waarbij ioctlsocket () zegt dat er 1 byte in de receive buffer staat :?)

[ Voor 70% gewijzigd door .oisyn op 01-05-2003 17:00 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • The End
  • Registratie: Maart 2000
  • Laatst online: 13:32

The End

!Beginning

.oisyn schreef op 01 May 2003 @ 16:51:
Met ICMP vindt ik ook geen terugkomende pakketjes

.edit: The End: Dat staat bij de send () en sendto () functies, maar daar krijg ik geen error. Die error krijg ik juist bij recvfrom () (waarbij ioctlsocket () zegt dat er 1 byte in de receive buffer staat :?)
Bij mij staat het bij de recv() en recvfrom() er ook bij. (Ik heb een versie uit oktober 2002 met de platform SDK geinstalleerd.)

[ Voor 11% gewijzigd door The End op 01-05-2003 17:08 . Reden: +link ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

Topicstarter
Hmz je hebt gelijk, ik deed een search naar jouw passage, en toen vond ie alleen send () en sendto (). Maar bij recv () en recvfrom () staat ie idd ook |:(

Maar toch blijf ik het raar vinden dat ie dan zegt dat er 1 byte in de receive buffer staat, en dat ie bij de receive pas die error geeft.

[ Voor 32% gewijzigd door .oisyn op 01-05-2003 17:32 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • PommeFritz
  • Registratie: Augustus 2001
  • Laatst online: 10-07 04:13

PommeFritz

...geen friet

Kun je een stukje code posten? Ik ben nieuwsgierig.

FireFox - neem het web in eigen hand


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

.oisyn schreef op 01 May 2003 @ 17:22:
Hmz je hebt gelijk, ik deed een search naar jouw passage, en toen vond ie alleen send () en sendto (). Maar bij recv () en recvfrom () staat ie idd ook |:(

Maar toch blijf ik het raar vinden dat ie dan zegt dat er 1 byte in de receive buffer staat, en dat ie bij de receive pas die error geeft.
Lijkt mij een trigger onder het motto van 'zorgen dat het programma gaat kijken zodat we kunnen failen op de vervolgactie'.

* curry684 heeft nog geen kans gehad om docs door te spitten overigens... :Z

Professionele website nodig?


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

Topicstarter
PommeFritz schreef op 01 May 2003 @ 19:56:
Kun je een stukje code posten? Ik ben nieuwsgierig.
niet echt, aangezien we werken aan een officieel spel ;)
Maar het ziet er ongeveer zo uit:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Socket sock;
HANDLE stopEvent; // signaal van buitenaf dat er gestopt moet worden

int readThread ()
{
    HANDLE readEvent = WSACreateEvent ();
    WSAEventSelect (sock, readEvent, FD_READ);
    HANDLE events[] = { stopEvent, waitEvent };
    Datagram data;

    while (true)
    {
        if (WaitForMultipleObjects (events, 2, INFINITE) == WAIT_OBJECT_0)
            return 0;  // stopEvent triggered

        while (sock.available ())  // deze retourneert dus 1 byte
        {
            sock.read (data);  // hier krijg ik de SOCKET_ERROR met WSAECONNRESET
            
            // doe wat met de data
        }

        ResetEvent (readEvent);
    }
}


en Socket::available () is zo geimplementeerd:
C++:
1
2
3
4
5
6
unsigned long Socket::available ()
{
    unsigned long len;
    ioctlsocket (s, &len, FIONREAD);
    return len;
}


En dan zodra ik een sendto () doe op de socket, wordt readEvent meteen getriggered, en staat er volgens ioctlsocket () 1 byte in de leesbuffer (maar een error geeft als ik 'm uit wil lezen)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • The End
  • Registratie: Maart 2000
  • Laatst online: 13:32

The End

!Beginning

Volgens mij moet je wel controlleren wat ioctlsocket returned...
code:
1
2
3
4
5
6
7
8
9
10
11
unsigned long Socket::available () 
{
    long ErrorCode = 0;
    unsigned long len = 0; //ik initialiseer ook alles op 0 btw 
    if((ErrorCode = ioctlsocket (s, &len, FIONREAD)) != 0)
    {
          printf(_T("ioctlsocket error %ld"),ErrorCode); //ofzo
          return 0;
    }
    return len; 
}

[ Voor 8% gewijzigd door The End op 02-05-2003 16:38 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

Topicstarter
die geeft dus geen error terug, dat is het probleem

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • PommeFritz
  • Registratie: Augustus 2001
  • Laatst online: 10-07 04:13

PommeFritz

...geen friet

Ik gok erop dat je je socket verkeerd aanmaakt, omdat het zo is (zoals je zelf al aangaf) dat UDP connectionless is. Het sturen van een bericht via een UDP socket naar een destination lukt gewoon ook als die destination er niet is (daar is het UDP voor!).

Laat eens zien hoe je de server socket en de client socket aanmaakt?

(ik zie trw. dat het Winsock specifiek is allemaal.... daar weet ik niet zo veel van, maar laat toch maar zien)

FireFox - neem het web in eigen hand


Verwijderd

Hier:
http://tangentsoft.net/ws...es/bsd-compatibility.html (zoek op recvfrom) wordt volgens mij het zelfde "probleem" genoemd.

Wat curry684 ook al zei, het lijkt manier om de applicatie te laten lezen zodat de fout opgemerkt kan worden. Het is udp, dus de send is een soort "fire en forget", maar er komt wat later ("delayed" dus) toch een relevante ICMP error van terug, die op deze manier bij de applicatie door kan komen. Dit is natuurlijk wat gokwerk, ik heb ook nog nergens gelezen dat dit echt zo bedoeld is.

Je hebt unicast gebruikt, geen broadcast? Bij broadcast zou ik dit niet verwachten, want het feit dat er 1 host niet meer luistert zegt dan niet zoveel.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

Topicstarter
PommeFritz schreef op 02 mei 2003 @ 20:08:
Ik gok erop dat je je socket verkeerd aanmaakt, omdat het zo is (zoals je zelf al aangaf) dat UDP connectionless is. Het sturen van een bericht via een UDP socket naar een destination lukt gewoon ook als die destination er niet is (daar is het UDP voor!).
Waaruit maak jij op dat ik 'm verkeerd aanmaak? Voor de rest gaat alles goed. De replies van curry684 en Offspring lijken mij een goede verklaring. Er komt waarschijnlijk een ICMP pakketje terug die aangeeft dat de applicatie die voorheen op die socket zat te luisteren niet meer luistert, en dus krijg ik een WSAECONNRESET. Dat is op zich vreemd, want hoe kun je een connectie resetten als er geen is. Maar het staat toch zo in de MSDN:
WSAECONNRESET: The virtual circuit was reset by the remote side executing a hard or abortive close. For UPD sockets, the remote host was unable to deliver a previously sent UDP datagram and responded with a "Port Unreachable" ICMP packet. The application should close the socket as it is no longer usable
Laat eens zien hoe je de server socket en de client socket aanmaakt?
Heb hier niet de code, maar uit mijn hoofd (even zonder error checking):
C++:
1
2
3
4
5
6
7
8
bool Socket::create (const net::Address & pAddr, short pPort)
{
    sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);

    sockaddr_in addr = { AF_INET, htons (pPort) };
    addr.sin_addr.S_un.S_addr = pAddr.ip;
    bind (sock, reinterpret_cast<sockaddr *> (&addr), sizeof (addr));
}
Verwijderd schreef op 02 mei 2003 @ 23:54:
Hier:
http://tangentsoft.net/ws...es/bsd-compatibility.html (zoek op recvfrom) wordt volgens mij het zelfde "probleem" genoemd.
idd ja. Ok, dan doe ik het maar af als "expected behaviour" :)
Je hebt unicast gebruikt, geen broadcast? Bij broadcast zou ik dit niet verwachten, want het feit dat er 1 host niet meer luistert zegt dan niet zoveel.
unicast ja. Het gaat een beetje zo:
- server luistert op socket
- client stuurt connect request packet naar server
- server zegt ok
... wat game data tussen de server client ...
- client's proces stopt abrubt, dus reageert niet meer
- server stuurt een bericht naar client
- server krijgt direct daarna een error bij de eerstvolgende receive (WSAECONNRESET)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1