viric ([info]viric) wrote,
@ 2007-04-27 19:37:00
Previous Entry  Add to memories!  Tell a Friend!  Next Entry
Entry tags:programado

TCP koŝmaro
Hodiaŭ mi eksciis gravan aferon pri TCP. Imagu la programeron:

{
  s = socket(PF_INET, SOCK_STREAM, 0);
  connect(s, ...);
  send(s, ...);
  close(s);
}

Laŭ vi, ĝi funkcias por sendi datumojn per TCP, ĉu ne? Senprobleme la datumoj alvenos la alian flankon, ĉu ne? NE, kaze ke la alia flanko ion sendas.


Se la alia flanko nenion sendas, ĉio bonos. Ni sendos la datumojn, poste FIN, kaj ĉion bonan.

Sed se nia TCP-monto (tcp stack) ricevis datumojn por la koncerna konektingo (socket), sed la programo ilin ne legas (t.n. read()), je nia close() nia TCP-monto sendos ne FIN, sed RST.

Ĝuste, kiam la alia flanko ricevas nian RST, ĝi forĵetas ĉiujn datumojn de la TCP-monto, kiujn la riceva programo ankoraŭ ne legis.

Do jen, nia programo sendis blindfide datumojn, kaj ili probable ne atingos la aliflankan programon.

Ve, kiom malfacilis tion malkovri! Mi ne trovis en la RFC aŭ en la libroj de Stevens tiom klaran eksplikon. La plej simila ekspliko kiun ili tie diras (kiu donas konsekvence la ĵusan rakonton) estas: Por certiĝi ke la programo de la alia flanko ricevis niajn sendaĵojn, ni devas atendi per recv(), kaj ricevi nulon (0).. Certe, se ricevi nulon, tio signifas ke la alia flanko sendis FIN, ne RST. Kaj ĝi devas sendi FIN nur se la programo (ne nur la TCP-monto) ricevis ĉiujn datumojn. Tial nia simpla ne-ricevanta programo povas sendi RST, kaj forfiki la datumojn ankoraŭ ne legitajn de la aliflanka programo.

Cetere, neniel gravas ĉu antaŭ ol sendi ni ruligas:
  shutdown(SHUT_RD);


La ĝenerala solvo estas ĉiam fari legojn kaj skribojn en select()-buklo. Eĉ se ni volas nur sendi.


(Post a new comment)


[info]max12354
2007-04-27 07:34 pm UTC (link)
Terure, kiu specifajxoj!

Cxu eblas reagordi la nian flankon de interfaco tiel ke gxi cxiam sendu na FIN sed ne na RST? Ja fakte malbonajxon faras sistema programo en _nia_ komputilo!

(Reply to this)(Thread)


[info]viric
2007-04-27 07:56 pm UTC (link)
Eblas sendi FIN per shutdown(SHUT_WR).

Sed je fermo de la konektingo (close()), ĝi tutegale sendos RST se vi vere ne legis.

La operacisistemo nenion malbonan faras. Ĝi agas ĝuste. Se vi ne legis, ĝi sendas RST, por ke la alia flanko sciu.

Tiu uzo de shutdown(SHUT_WR) por sendi FIN.... nu, mi pensas ke tiun shutdown() oni aldonis al la listo de sistemaj vokoj POST la dezajno. :) Tial per ĝi eblas iom trompi la alian flankon pri la lego de datumoj.

Sed kial trompi? Se vi vere volas forĵeti la legaĵojn en via programo, vi devas tion kodigi. :) Se ĉiuj sekvas tiun sistemon, eblas _certiĝi_ ke la aliflanka programo legis la datumojn - tre grava informo!

(Reply to this)(Parent)


[info]viric
2007-04-27 07:58 pm UTC (link)
Eblas per shutdown(SHUT_WR) sendi FIN, sed je close(), la RST estos sendita se vi ne legis.

Fakte tre bonas tiuj postuloj! Simple mi ilin ne konsciis antaŭe. Tiel, eblas preskaŭ certe scii ĉu la alia programo legis la datumojn (krom en la kazo de shutdown(SHUT_WR), trompeme).

(Reply to this)(Parent)(Thread)


[info]viric
2007-04-27 07:59 pm UTC (link)
Argh. Mi pensis ke la unua ne venis al Liveĵournal. Liveĵournal diris ke mia sendo ne funkciis.
Do jen, vi havas du respondojn, maks!

(Reply to this)(Parent)


[info]max12354
2007-04-28 03:43 am UTC (link)
Tamen nia programo kaj TCP sistemo estas ne sinkronaj. Do inter niaj read() (kiu donas ke nenio plu estas por legi) kaj close() povas veni ankoraux datumoj.

Ankaux, cxu povas rezultigxi ke lego de la datumoj (nebezonataj) pligrandigas la retan trafikon?

(Reply to this)(Parent)(Thread)


[info]viric
2007-04-28 08:14 am UTC (link)
Ne. Kiam vi ricevas 0 bajtojn, tio signifas ke oni ne plu sendos.

(Reply to this)(Parent)


Create an Account
Forgot your login?
Login w/ OpenID
English • Español • Deutsch • Русский…