Java týden Body zdarma
Využij podzimních slev a získej od nás až 40 % bodů zdarma! Více zde
Pouze tento týden sleva až 80 % na Java e-learning!
Avatar
xmms
Člen
Avatar
xmms:9. října 0:16

Dělám TCP a UDP server klient a chci nastavit pro sokety nějaký timeout pár sekund, aby navázané mrtvé spojení nezůstalo otevřené až do příštího restartu počítače. Zdroják je část ze stránek https://docs.microsoft.com/…-server-code

Zkusil jsem:

SOCKET ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
        printf("socket failed with error: %ld\n", WSAGetLastError());
        WSACleanup();
        return 1;
}

struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;

int timeout = 10000;

if ((setsockopt(ListenSocket, SOL_SOCKET, SO_SNDTIMEO, (const char *)&timeout, sizeof(tv))) < 0) {
        perror("Error setsockopt");
}

Chci docílit: Parametr SO_RCVTIMEO způsobí, že se spojení ukončí, když neprobíhá komunikace. Je tam ještě SO_SNDTIMEO, který je pro send timeout, ten jsem nepochopil, ani nenašel, jak to funguje. Po nastavení send timeout se mi to nijak neprojevilo a spojení se neukončuje.

K čemu přesně slouží a jak funguje SO_SNDTIMEO? A je potřeba to nastavovat?

 
Odpovědět 9. října 0:16
Avatar
Martin Dráb
Redaktor
Avatar
Odpovídá na xmms
Martin Dráb:9. října 16:56

Parametr SO_RCVTIMEO způsobí, že se spojení ukončí, když neprobíhá komunikace

Myslím, že jen způsobí to, že recv ti vrátí timeout v případě, že během daného časového intervalu nepřišla žádná data (nezůstane zablokováno cca navždy). Spojení ale zrušeno není, dokud neuděláš shutdown.

SO_SNDTIMEO

Ač se to nezdá, operace send může být také blokující, protože je za standardních podmínek dokončena, až když jsou data úspěšně odeslána (což teoreticky nemusí být hned). Takže SO_SNDTIMEO řeší tyto (ne moc často se stávající) případy.

Nahoru Odpovědět 9. října 16:56
2 + 2 = 5 for extremely large values of 2
Avatar
xmms
Člen
Avatar
Odpovídá na Martin Dráb
xmms:9. října 19:30

Zkoušel jsem to a po zavolání send() program pokračuje dál, zatímco se odesílají data. Zkoušel jsem poslat 500MB a odesílání dat proběhlo až dokonce, i když jsem hned po send() ukončil program. Windows si to nějak převezme a pokračuje v odesílání dat i po skončení programu.

 
Nahoru Odpovědět 9. října 19:30
Avatar
Martin Dráb
Redaktor
Avatar
Odpovídá na xmms
Martin Dráb:9. října 21:22

V dokumentaci pro funkci send se píše:

The successful completion of a send function does not indicate that the data was successfully delivered and received to the recipient. This function only indicates the data was successfully sent.

Tzn. send skončí, když dojde k úspěšnému odeslání dat (v zásadě byla zpracována do takového stavu, že mohou putovat na druhou stranu), ale neříká nic o tom, zda-li či kdy se všechna ta data podaří druhé straně přijmout. Což dává smysl, protože u protokolů jako TCP/IP může přenos trvat teoreticky hodně dlouho, pokud se třeba občas něco ztratí.

Tak jsem mínil můj předchozí příspěvek.

https://docs.microsoft.com/…insock2-send

Nahoru Odpovědět 9. října 21:22
2 + 2 = 5 for extremely large values of 2
Avatar
xmms
Člen
Avatar
Odpovídá na Martin Dráb
xmms:10. října 11:21

Chová se to různě. Když po zavolání send() se ukončí program přes exit(), tak se spojení ukončí a zruší se posílání dat. Když ten konzolový program ukončím křížkem, tak se pošlou všechna data, to pokračuje někde na pozadí v systému. Jen nevím, kde byl uložen buffer 500MB, který jsem posílal. Ve správci úloh bylo vidět, že po skončení odesílání dat spadlo celkové obsazení paměti, ale nebylo to vidět na žádném konkrétním procesu.

 
Nahoru Odpovědět 10. října 11:21
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Martin Dráb
Redaktor
Avatar
Odpovídá na xmms
Martin Dráb:11. října 11:10

Chová se to různě

To záleží (jak píše dokumentace), jak s těmi sockety program pracuje. Pokud zavoláš exit, zřejmě nedojde k rozumnému ukončení spojení (nezavolá se na ně shutdown) a standardní chování při ukončení procesu (platí to tedy přímo i pro jednotlivá vlákna) spočívá ve zrušení všech nedokončených I/O požadavků.

Pokud se ale někde později na ten socket volá shutdown, tak se spojení ukončí korektně a (podle dokumentace) se fyzicky odešlou všechna data, co jsi poslal přes send.

Obecně je asi problém ale definovat, co to znamená, že data byla odeslána, protože třeba TCP/IP neřeší, jakým způsobem je implementována linková a fyzická vrstva. A aplikaci také nezajímá, jak a kdy odesílaná data procházejí vrstvami vyššími (síťová, transportní), protože to si zařizuje TCP/IP samo.

Nicméně se teoreticky může stát, že volání send bude blokující (můžeš zkusit například odesílat data z více vláken na stejný socket, nebo volat send v cyklu).

Nahoru Odpovědět 11. října 11:10
2 + 2 = 5 for extremely large values of 2
Avatar
xmms
Člen
Avatar
xmms:11. října 15:26

Blokující ten send nebyl. Když ve visual studiu udělám step over přes funkci send, začnou se posílat data na pozadí a já můžu krokovat další řádky programu. Mezitím se přijímají data na druhém konci.
Zkoušel jsem to přes internet na datech 500 MB a všechna data dorazila.

 
Nahoru Odpovědět 11. října 15:26
Avatar
xmms
Člen
Avatar
xmms:11. října 15:44

A záleží opravdu na té funkci shutdown. Pokud se program ukončí bez zavolání shutdown, tak se spojení zruší. Pokud se ukončí až po jejím zavolání, tak program skončí, ale na pozadí se dál posílají data. To je nádhera, už to za chvíli budu umět :)

 
Nahoru Odpovědět 11. října 15:44
Avatar
Martin Dráb
Redaktor
Avatar
Odpovídá na xmms
Martin Dráb:11. října 19:13

Podle dokumentace může send v případě socketu v neblokujícím režimu vrátit chybu EWOULDBLOCK, kterou říká, že daná operaci by aktuální vlákno zablokovala (i třeba jen na takovou dobu, které si nepovšimneš ani při Step over). Trik je v tom, že blokující send si data překopíruje/zpra­cuje někam "k sobě", takže je nemusíš držet v daném bufferu. Což neplatí, pokud bys prováděl socketové operace asynchronně (tam musíš data držet v daném bufferu, dokud operace neskončí).

Také se mi v praxi nestalo, že by mi send nějak výrazně blokoval. Na druhou stranu jsem jej používal jenom pro síťovou komunikaci, ne třeba pro komunikaci přes infraport (AF_IRDA), kde by se to asi stát mohlo (vzhledem k rychlosti a odlišnosti infraportu). Proto je tam to nastavení SENDTIMEO

Nahoru Odpovědět 11. října 19:13
2 + 2 = 5 for extremely large values of 2
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 9 zpráv z 9.