Používám send() místo write(), které nezpracovávají žádný signál:
bzero(buffer, MAX_SIZE_BUFFER);
n = read(sockfd, buffer, MAX_SIZE_BUFFER - 1);
printf("after read%d\n", n);
if (n <= 0)
{
break;
}
n2 = send(newsockfd, buffer, n, MSG_NOSIGNAL);
if (n2 == -1)
{
close(sockfd);
close(newsockfd);
return;
}
if (n2 != n)
{
break;
}
Programování soketů může být poměrně složité, protože o chybě často víte až mnohem později.
Pokud se například počítač, na který zapisujete, nenormálně vypne, volání zápisu může být úspěšné (protože jste byli schopni zapisovat do vnitřních vyrovnávacích pamětí operačního systému), ale během zavíracího volání selže.
Pokud nemáte na aplikační vrstvě způsob ověření, zda je soket aktivní (tj. odeslání zprávy a vyžadování odpovědi v určitém časovém období), nemůžete to vědět. Pokud používáte standardní protokol, může již existovat něco pro zpracování chyb.
Krátká odpověď tedy zní, že musíte zkontrolovat návratnost chyb z téměř každého volání, které se dotkne soketu (čtení, zápis, zavření atd...).
Způsob, jak zkontrolovat, zda můžete zapisovat do soketu, je překvapivě zkusit do něj zapisovat :-)
Pokud byla zásuvka uzavřena, dostanete -1
návratový kód z write
a můžete prozkoumat errno
abyste viděli, v čem byl problém.
Pokud je soket stále platný, ale momentálně nemůžete zapisovat žádná data, write
vrátí 0. read
volání se také chová podobným způsobem a vrací -1
pokud je problém.
V podstatě pro write
:
- pokud dostanete zpět
-1
, došlo k problému a měli byste zkontrolovaterrno
zjistit, zda je obnovitelný nebo smrtelný. - Pokud dostanete zpět
0
, pak v tuto chvíli nemůžete nic psát (může to být nevyřízená síť nebo jiný problém, ale rozhodně ne (zatím) fatální). - Pokud získáte hodnotu nižší, než jste chtěli, pak nějaké dat byla odeslána. Upravte si ukazatele, abyste mohli zkusit poslat zbytek v příštím cyklu. Ne předpokládat kladnou návratovou hodnotu znamená, že byl odeslán celý blok.
- Pokud se vám vrátí stejné číslo, jako je počet bajtů, které jste se pokusili odeslat, byla k doručení přijata celá vyrovnávací paměť.
- Pokud dostanete zpět více, než jste požadovali, pošlete e-mail vývojářům jádra s nějakým jízlivým komentářem. To se Linusovi a spol. bude líbit :-)
Aktualizace: Jak caf upozornil v komentářích, zapomněl jsem vzít v úvahu zpracování signálu. Signál přerušeného potrubí nebo write
musíte ignorovat selže interně zvýšením signálu.
Můžete to provést vložením:
struct sigaction new_actn, old_actn;
new_actn.sa_handler = SIG_IGN;
sigemptyset (&new_actn.sa_mask);
new_actn.sa_flags = 0;
sigaction (SIGPIPE, &new_actn, &old_actn);
než začnete používat funkce zásuvky. Poté můžete použít:
sigaction (SIGPIPE, &old_actn, NULL);
pro obnovení předchozího zpracování signálu.