Toon posts:

[C++] TCP socket disconnect afhandelen

Pagina: 1
Acties:

Onderwerpen


  • Bolk
  • Registratie: februari 2001
  • Niet online

Bolk

Change the equation.

Topicstarter
Hoi!

Voordat iedereen me uitlacht om onderstaande code (:P); ik ben over het algemeen meer PHP-er met een beetje C# kennis (lerende) maar in verband met een game-plugin word ik geforceerd aan de C++ gezet ;) Ik loop tegen een probleem aan en ik kom er niet aan uit.

Situatie
Voor een racespel heb ik een SDK gedownload waarin ze voorbeeldcode geven van een plugin. De plugin geeft mij iedere halve seconde kant en klare data uit de game via een struct. Ik kan dit wegschrijven in een file en dan weer uitlezen wat ik vroeger gedaan heb, maar wil nu het met een socket server oplossen. Met hier en daar wat hulp en veel gegoogle heb ik een basic socket server die het prima doet. Totdat ik erachter kwam dat een bokkende verbinding nog wel eens roet in het eten kan gooien. Het is de bedoeling dat dit 24/7 gaat draaien, zodat er realtime data op een website gepubliceerd kan worden.

De plugin dient als een server en met een C# app als client stuur ik iedere seconde data naar de server (connectie blijft dus continu open staan) en krijg zo m'n data uit de game en verwerk ik het verder met C#.

De server in de plugin draait in een aparte thread.

Probleem
Als de connectie correct wordt afgesloten (dus via C# met een socket close) dan wordt de thread van de server gemarkeerd als finished. De thread wordt dan via de workerthread in de plugin zelf (van de game) weer herstart. Dit werkt allemaal prima.

Het gaat mis wanneer er een verbinding wegvalt. Denk hierbij aan een internet connectie of als ik de kabel eruit trek. Op een of andere manier breaked-ie niet uit de onderstaande while loop:


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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
DWORD WINAPI Checker(void *)
{
    WSADATA wsaData;
    sockaddr_in local;
    int wsaret = WSAStartup(0x101, &wsaData);
    char buf[2];
    SOCKET client;
    sockaddr_in from;
    int fromlen;

    int nret;

    local.sin_family=AF_INET;
    local.sin_addr.s_addr=INADDR_ANY;
    local.sin_port=htons(atoi(port));

    server=socket(AF_INET,SOCK_STREAM,0);
    nret = bind(server,(sockaddr*)&local,sizeof(local));

    if (nret == SOCKET_ERROR)
    {
        nret = WSAGetLastError();
        //MessageBox(NULL, "ERROR Bind", "socketIndication", MB_OK);
        WSACleanup();
        return 0;
    }

    nret = listen(server, 1);
    
    if (nret == SOCKET_ERROR)
    {
        nret = WSAGetLastError();
        //MessageBox(NULL, "ERROR Listen", "socketIndication", MB_OK);
        WSACleanup();
        return 0;
    }

    fromlen = sizeof(from);

    client = accept(server, (struct sockaddr*)&from,&fromlen);

    if(client == INVALID_SOCKET)
    {
        nret = WSAGetLastError();
        //MessageBox(NULL, "ERROR Accept", "socketIndication", MB_OK);
        WSACleanup();
        return 0;
    }

    while(client != INVALID_SOCKET && recv(client, buf, 2, 0) != SOCKET_ERROR)
    {
        memset(&OurInfo, '\0', sizeof(OurInfo));

        // Print general scoring info
        //[*KNIP*] Hier maak ik de data op die ik wil gaan verzenden

        if(send(client, OurInfo, strlen(OurInfo), 0) == SOCKET_ERROR) break;
    }

    closesocket(client);
    closesocket(server);
    WSACleanup();
    
    serverAlive = false;
    
    //MessageBox(NULL, "Thread should close here...", "socketIndication", MB_OK);

    return 0;
}


Kan iemand mij vertellen hoe ik een disconnect het beste kan detecteren? Wanneer de connectie wegvalt dan blijft, volgens netstat -an, de verbinding op ESTABLISHED staan. Logisch, want op een of andere manier kom ik niet uit die while loop. Ik krijg dan de volgende error voor m'n kiezen van m'n C# client app:

An existing connection was forcibly closed by the remote host

Wat volgens dit betekent dat een connectie wel gemaakt wordt, maar dat er geen data verzonden kan worden door dat er geen accept plaats vindt?

Ik heb overwogen om over te stappen naar UDP en ook om iedere keer de connectie af te sluiten en weer opnieuw op te bouwen (dus zonder de while loop), want eigenlijk betekent dat ik iedere seconde een nieuwe thread (+ socket server) aan moet maken.

Voordat ik dat soort truukjes ga uithalen wilde ik liever het eerst hier vragen. Hoop dat iemand me kan helpen :)

Ik bespeur hier een zekere mate van onethische logica.


  • splrf
  • Registratie: november 2005
  • Laatst online: 21-09 16:28
Volgens mij blokkeert recv en wacht het gewoon tot er data beschikbaar is wat dus nooit gaat gebeuren als er aan de verzend kant niet goed afgesloten is.. Je kunt de socket op nonblocking zetten en pollen of er al data is. Dat heeft als nadeel dat je proces de hele tijd weer wakker wordt en een beetje CPU tijd eet en afhankelijk van je slaapperiode en dat je proces niet gelijk reageert.
Ik heb heel even gekeken of ik dat kan vinden, maar ik ben niet enorm thuis in WinSock en msdn is een beetje vaag hierover

Maar het blijkt dat je eventueel ook een timeout kunt zetten op recv. Lijkt me in dit geval het handigst aangezien je toch elke seconde data stuurt :)
http://msdn.microsoft.com...ry/ms740532(v=VS.85).aspx

  • Killemov
  • Registratie: januari 2000
  • Laatst online: 22-09 16:22

Killemov

Ik zoek nog een mooi icooi =)

+1 Timeout. Dit lijkt het enige te zijn dat gewoon werkt.

Hey ... maar dan heb je ook wat!


  • leuk_he
  • Registratie: augustus 2000
  • Laatst online: 21-09 12:08

leuk_he

1. Controleer de kabel!

In jouw geval krijg je de boel denk ik weer met een timeout of een error status op recv aan de gang. (elke keer disconnecten en connecten werkt niet omdat het ook midden in een connect -send/recevice disconnect kan hangen).

Echter op een wat grotere server schaalt het niet als je 1 thread per client hebt, (elke thread heeft zijn eigen stack van zeg 2MB, en overhead om te switchemn, dus meer als een paar dozijn threads is alleen te doen als je precies weet wat je doet. ).


Je hebt dat de keus met select of met windows notification te werken. (of overlapped io maar daar heb ik nooit mee gewerkt omdat dat niet in alle windows versies ondersteund werd)

In jouw voorbeeld zou je een apparte thread/message notificaiton loop maken na de accept. Maar ook daar zijn voorbeelden van te vinden.

Leg het ook eens tegen deze source, maar die doet hetzelfde volgens mij:
http://msdn.microsoft.com.../ms737593%28VS.85%29.aspx

Het kan inderdaad best lang duren voordat een thread een timeout geeft.

Need more data. We want your specs. Ik ben ook maar dom. anders: forum, ff reggen, ff topic maken
En als je een oplossing hebt gevonden laat het ook ujb ff in dit topic horen.


  • Bolk
  • Registratie: februari 2001
  • Niet online

Bolk

Change the equation.

Topicstarter
Time out ligt natuurlijk redelijk voor de hand. Dat ik daar niet eerder aan gedacht heb! Thanks!

De server heeft maar 1 connectie. Ik hoef daarom niet aan de gang met asynchrone threads etc.

Ik heb nu met setsockopt zowel de send- als receivetimeouts gezet op 10 seconden. Eens kijken of dit de oplossing is...

Ik bespeur hier een zekere mate van onethische logica.


  • MSalters
  • Registratie: juni 2001
  • Laatst online: 14-09 11:08
leuk_he schreef op zondag 03 oktober 2010 @ 22:40:
Echter op een wat grotere server schaalt het niet als je 1 thread per client hebt, (elke thread heeft zijn eigen stack van zeg 2MB, en overhead om te switchemn, dus meer als een paar dozijn threads is alleen te doen als je precies weet wat je doet. ).

Je hebt dat de keus met select of met windows notification te werken. (of overlapped io maar daar heb ik nooit mee gewerkt omdat dat niet in alle windows versies ondersteund werd)
Overlapped I/O werkte al in NT 3.1, dus daar hoef je je geen zorgen over te maken. Ja, Windows 95 kon 't niet, maar die had sowieso issues met multi-threading.

Niet alleen is overlapped I/O al heel lang ondersteund, het is ook een stuk efficienter dan de twee alternatieven die je noemt. Met name de combinatie met I/O completion ports zorgt ervoor dat een multi-threaded server maximaal rendement uit een beperkt aantal CPU's haalt.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • farlane
  • Registratie: maart 2000
  • Laatst online: 20-09 22:56
Je probleem lijkt trouwens beter te passen bij UDP: de nadruk lijkt meer op latency te liggen dan op betrouwbaarheid.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • Olaf van der Spek
  • Registratie: september 2000
  • Niet online
farlane schreef op maandag 04 oktober 2010 @ 16:13:
Je probleem lijkt trouwens beter te passen bij UDP: de nadruk lijkt meer op latency te liggen dan op betrouwbaarheid.
Waarom zou UDP in dit geval een significant lagere latency dan TCP opleveren?

  • farlane
  • Registratie: maart 2000
  • Laatst online: 20-09 22:56
Olaf van der Spek schreef op maandag 04 oktober 2010 @ 16:27:
Waarom zou UDP in dit geval een significant lagere latency dan TCP opleveren?
Misschien niet latency perse ( alhoewel dat vanuit het prespectief van de applicatie zeker wel zo zal zijn omdat bepaalde TCP algorithmen nou eenmaal voor vertragingen zorgen. Of dat significant is ligt aan de situatie ), maar vaak is het zo dat als je tegen de betrouwbaarheid van TCP gaat te vechten ( zoals bv de receive timeout, maar er zijn dan ook nog de connect timeout en linger timeout ) dat UDP een handiger protocol is.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • Olaf van der Spek
  • Registratie: september 2000
  • Niet online
farlane schreef op maandag 04 oktober 2010 @ 23:18:
maar vaak is het zo dat als je tegen de betrouwbaarheid van TCP gaat te vechten ( zoals bv de receive timeout, maar er zijn dan ook nog de connect timeout en linger timeout ) dat UDP een handiger protocol is.
Timeout handling in de app is heel normaal voor TCP, dus dat lijkt me geen reden om maar UDP te gebruiken.

  • leuk_he
  • Registratie: augustus 2000
  • Laatst online: 21-09 12:08

leuk_he

1. Controleer de kabel!

Olaf van der Spek schreef op dinsdag 05 oktober 2010 @ 12:21:
[...]

Timeout handling in de app is heel normaal voor TCP, dus dat lijkt me geen reden om maar UDP te gebruiken.
Als je alle status informatie van de client naar de server wilt sturen, dan moet je in de client en de server toch weer bij gaan houden hoeveel data er verstuurd is als je een timeout krijgt ,zodat je weet waar je moet herstarten na een timeout.

Als je dat allemaal hebt ingebouwd dan kan het zijn dat je concludeerd dat UDP net zoveel werk was geweest. Verkijk je niet op het "reliable" onderdeel, want als je timeouts gaat afvangen dan besef je dat het in geval van timeout juist unreliable was.

Ook in UDP moet je timeouts(/misssende/dubbele data) afvangen, dus wat dat betreft heb je gelijk dat het geen reden is over stappen naar udp.

Need more data. We want your specs. Ik ben ook maar dom. anders: forum, ff reggen, ff topic maken
En als je een oplossing hebt gevonden laat het ook ujb ff in dit topic horen.


  • Olaf van der Spek
  • Registratie: september 2000
  • Niet online
leuk_he schreef op dinsdag 05 oktober 2010 @ 14:01:
Als je alle status informatie van de client naar de server wilt sturen, dan moet je in de client en de server toch weer bij gaan houden hoeveel data er verstuurd is als je een timeout krijgt ,zodat je weet waar je moet herstarten na een timeout.
Natuurlijk niet. Als de TCP verbinding faalt start je vanaf 0.

  • farlane
  • Registratie: maart 2000
  • Laatst online: 20-09 22:56
Olaf van der Spek schreef op dinsdag 05 oktober 2010 @ 12:21:
Timeout handling in de app is heel normaal voor TCP, dus dat lijkt me geen reden om maar UDP te gebruiken.
Timeout handling is verplicht voor een robuuste applicatie, maar de timeouts van TCP zijn niet voor niets langer dan de TS wil. Als je daar tegen gaat vechten kun je beter een ander protocol pakken waarbij UDP een redelijke optie zou zijn.

Als je 'realtime' data ( en ik gebruik realtime hier als met 'een kleine latency' ) wilt weergeven kun je je afvragen of het zin heeft om na 30s te horen dat de verbinding weg is, dat had je ook na bv 1500ms al kunnen concluderen )

BTW, ga je zelf ook nog tips/oplosssingen geven aan de TS of blijf je zo doordrammen?

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • Olaf van der Spek
  • Registratie: september 2000
  • Niet online
farlane schreef op dinsdag 05 oktober 2010 @ 19:09:
Timeout handling is verplicht voor een robuuste applicatie, maar de timeouts van TCP zijn niet voor niets langer dan de TS wil. Als je daar tegen gaat vechten kun je beter een ander protocol pakken waarbij UDP een redelijke optie zou zijn.
Ik zou het geen vechten noemen. Bovendien is het al vreemd dat er een timeout optreed, dat gebeurd alleen als er echt iets down gaat en dan helpt UDP echt niet.
Als je 'realtime' data ( en ik gebruik realtime hier als met 'een kleine latency' ) wilt weergeven kun je je afvragen of het zin heeft om na 30s te horen dat de verbinding weg is, dat had je ook na bv 1500ms al kunnen concluderen )
Misschien wel, maar de vraag is of dat nut heeft.
BTW, ga je zelf ook nog tips/oplosssingen geven aan de TS of blijf je zo doordrammen?
Dat heet gewoon discussieren. Is dat te lastig?

  • Bolk
  • Registratie: februari 2001
  • Niet online

Bolk

Change the equation.

Topicstarter
farlane schreef op dinsdag 05 oktober 2010 @ 19:09:
[...]

BTW, ga je zelf ook nog tips/oplosssingen geven aan de TS of blijf je zo doordrammen?
Ik vind de discussie anders best aardig. Aangezien ik ook UDP overwogen heb.

Anyway.. Met gepaste trots (*D) kan ik melden dat er nu keurig een restart optreedt na het toevoegen van de timeouts. Hier en daar nog wat vage errors maar die kan ik vast wel afvangen en waar nodig oplossen.

Bedankt iedereen!

Voor de search evt:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
DWORD WINAPI Checker(void *)
{
    WSADATA wsaData;
    sockaddr_in local;
    int wsaret = WSAStartup(0x101, &wsaData);
    char buf[2];
    SOCKET client;
    sockaddr_in from;
    int fromlen, optval;

    int nret;

    local.sin_family=AF_INET;
    local.sin_addr.s_addr=INADDR_ANY;
    local.sin_port=htons(atoi(port));

    server = socket(AF_INET, SOCK_STREAM, 0);
    nret = bind(server, (sockaddr*)&local, sizeof(local));

    if (nret == SOCKET_ERROR)
    {
        nret = WSAGetLastError();
        //MessageBox(NULL, "ERROR Bind", "socketIndication", MB_OK);
        WSACleanup();
        return 0;
    }

    optval = 10000;   // time out on recv
    nret = setsockopt(server, SOL_SOCKET, SO_RCVTIMEO, (char *)&optval, 4);

    if (nret == SOCKET_ERROR)
    {
        nret = WSAGetLastError();
        //MessageBox(NULL, "ERROR SO_RCVTIMEO", "socketIndication", MB_OK);
        WSACleanup();
        return 0;
    }

    optval = 10000;   // time out on send
    nret = setsockopt(server, SOL_SOCKET, SO_SNDTIMEO, (char *)&optval, 4);
    if (nret == SOCKET_ERROR)
    {
        nret = WSAGetLastError();
        //MessageBox(NULL, "ERROR SO_SNDTIMEO", "socketIndication", MB_OK);
        WSACleanup();
        return 0;
    }

    nret = listen(server, 1);
    
    if (nret == SOCKET_ERROR)
    {
        nret = WSAGetLastError();
        //MessageBox(NULL, "ERROR Listen", "socketIndication", MB_OK);
        WSACleanup();
        return 0;
    }

    fromlen = sizeof(from);

    client = accept(server, (struct sockaddr*)&from,&fromlen);

    if(client == INVALID_SOCKET)
    {
        nret = WSAGetLastError();
        //MessageBox(NULL, "ERROR Accept", "socketIndication", MB_OK);
        WSACleanup();
        return 0;
    }

    //while(client != INVALID_SOCKET) {
    while(client != INVALID_SOCKET && recv(client, buf, 2, 0) != SOCKET_ERROR)
    {
        memset(&OurInfo, '\0', sizeof(OurInfo));

        // Print general scoring info *KNIP*

        } 
                   
        if(send(client, OurInfo, strlen(OurInfo), 0) == SOCKET_ERROR) break;
    }
    //}

    closesocket(client);
    closesocket(server);
    WSACleanup();
    
    serverAlive = false;
    
    //MessageBox(NULL, "Thread should close here...", "socketIndication", MB_OK);

    return 0;
}

Ik bespeur hier een zekere mate van onethische logica.


  • Olaf van der Spek
  • Registratie: september 2000
  • Niet online
In plaats van alle WSACleanup calls zou je nog een wrapper kunnen schrijven zodat je die call maar een keer hebt. Of WSACleanup helemaal niet aanroepen. :p
Mooi dat het nu goed werkt.
Heb je de oorzaak van de timeouts al achterhaald?

[Voor 10% gewijzigd door Olaf van der Spek op 05-10-2010 20:44]


  • Bolk
  • Registratie: februari 2001
  • Niet online

Bolk

Change the equation.

Topicstarter
Ja dat zou kunnen voor het mooie inderdaad.

Ik had een bokkende internet verbinding. Ben er daarom per ongeluk eigenlijk achter gekomen. Ziggo voert hier nachtelijk nogal wat werk uit dus vandaar. De client draait hier 24/7 op een testserver en de server met de game staat in Haarlem. Vandaar de timeouts en het connectie probleem.

Maar het lijkt nu goed te werken. Nogmaals bedankt.

Offtopic: ligt het aan mij of is C++ uit z'n voegen gegroeid? Ik mis een beetje structuur maar dat kan natuurlijk ook aan mijn zwaar geringe kennis liggen. Krijg m'n hoofd er niet helemaal omheen zegmaar :P

Ik bespeur hier een zekere mate van onethische logica.


  • leuk_he
  • Registratie: augustus 2000
  • Laatst online: 21-09 12:08

leuk_he

1. Controleer de kabel!

Bolk schreef op dinsdag 05 oktober 2010 @ 21:02:
Offtopic: ligt het aan mij of is C++ uit z'n voegen gegroeid? Ik mis een beetje structuur maar dat kan natuurlijk ook aan mijn zwaar geringe kennis liggen. Krijg m'n hoofd er niet helemaal omheen zegmaar :P
offtopic:
Even afgezien het feit Of C++ uit zijn voegen gegroeid is, jij gebruikt daar voor 95% C, ik zie bijna geen C++ features. Dan zou je een socket class gebruiken. Niks mis mee om C te gebruiken

Need more data. We want your specs. Ik ben ook maar dom. anders: forum, ff reggen, ff topic maken
En als je een oplossing hebt gevonden laat het ook ujb ff in dit topic horen.


  • Bolk
  • Registratie: februari 2001
  • Niet online

Bolk

Change the equation.

Topicstarter
leuk_he schreef op dinsdag 05 oktober 2010 @ 21:54:
[...]


offtopic:
Even afgezien het feit Of C++ uit zijn voegen gegroeid is, jij gebruikt daar voor 95% C, ik zie bijna geen C++ features. Dan zou je een socket class gebruiken. Niks mis mee om C te gebruiken
Thanks, dat verklaart een hoop :)

Ik bespeur hier een zekere mate van onethische logica.


  • Olaf van der Spek
  • Registratie: september 2000
  • Niet online
Bolk schreef op dinsdag 05 oktober 2010 @ 21:02:
Offtopic: ligt het aan mij of is C++ uit z'n voegen gegroeid? Ik mis een beetje structuur
Wat mis je dan?
Pagina: 1


Nintendo Switch (OLED model) Apple iPhone 13 LG G1 Google Pixel 6 Call of Duty: Vanguard Samsung Galaxy S21 5G Apple iPad Pro (2021) 11" Wi-Fi, 8GB ram Nintendo Switch Lite

Tweakers vormt samen met Hardware Info, AutoTrack, Gaspedaal.nl, Nationale Vacaturebank, Intermediair en Independer DPG Online Services B.V.
Alle rechten voorbehouden © 1998 - 2021 Hosting door True

Tweakers maakt gebruik van cookies

Bij het bezoeken van het forum plaatst Tweakers alleen functionele en analytische cookies voor optimalisatie en analyse om de website-ervaring te verbeteren. Op het forum worden geen trackingcookies geplaatst. Voor het bekijken van video's en grafieken van derden vragen we je toestemming, we gebruiken daarvoor externe tooling die mogelijk cookies kunnen plaatsen.

Meer informatie vind je in ons cookiebeleid.

Sluiten

Forum cookie-instellingen

Bekijk de onderstaande instellingen en maak je keuze. Meer informatie vind je in ons cookiebeleid.

Functionele en analytische cookies

Deze cookies helpen de website zijn functies uit te voeren en zijn verplicht. Meer details

janee

    Cookies van derden

    Deze cookies kunnen geplaatst worden door derde partijen via ingesloten content en om de gebruikerservaring van de website te verbeteren. Meer details

    janee