Vienā un tajā pašā VpnService cilpā parādās divi simptomi, un abiem tiek vainots viens un tas pats: lasītājs, kas nekad neatgriežas, un rakstīšana, kas neizdodas ar ENOBUFS. Tie nav vienas kļūdas varianti. Iestrēdzis lasījums ir domstarpības par plūsmas kontroli ar partneri; neizdevusies rakstīšana ir pakete, ko saskarne nepieņems. Ja tos uzskata par vienu problēmu, jūs pavadīsiet dienu, regulējot buferus, kas nekad nav bijuši iesaistīti. Tālāk redzamais sadalījums ir tas, kā es izlemju, kuru cilpas pusi instrumentēt vispirms.

Viena cilpa, divi neatkarīgi atteices punkti

Jūsu serviss nolasa IP paketi no TUN faila deskriptora, pārbauda to un ieraksta atbildi atpakaļ tajā pašā deskriptorā. Viss, kas šajā ceļā salūzt, parādās vienā no šiem diviem izsaukumiem, tāpēc abi tiek ziņoti kā salauzts tunelis. Izsaukumiem ir atšķirīgi līgumi. Lasījums gaida, kad kodols jums nodos paketi, un rakstīšana nodod kodolam paketi, kuru tas drīkst atteikt.

Lasījumi ir tā vieglākā puse, par ko domāt. Lasījums, kas neko neatgriež, vai nu gaida satiksmi, kas nekad neienāk, vai gaida tāpēc, ka partneris pārstāja sūtīt.

Iestrēdzis lasījums ir plūsmas kontroles domstarpības

TUN ierīces lasīšana bloķē, līdz pakete ir pieejama. Tā ir projektēta uzvedība, un tāpēc pavediens, kas stāv read iekšienē, tukšā saitē izskatās normāli. Tas kļūst par iekāri, kad jūsu paša TCP steks turpina pieņemt datus no vietējās lietotnes, bet nekad nepaziņo pietiekamu logu, lai attālais partneris varētu nosūtīt vairāk. Partneris piepilda jūsu paziņoto logu, gaida ACK un loga atjauninājumu, un apstājas. Tad jūsu lasītājam nav ko atgriezt, un lietotne redz atvērtu un klusu savienojumu.

Biežākie iemesli ir steks, kas raksta ligzdā, neizsekojot paziņotajam logam, un otrs, kas aizmirst nosūtīt loga atjauninājumu pēc sava bufera iztukšošanas. No ārpuses tie izskatās identiski: baiti iziet, nekas neatgriežas, kļūda netiek izmesta. Lasīšanas pavediena bloķēšana parsēšanā, DNS izšķiršanā vai diska I/O rada tādu pašu simptoma formu nesaistīta iemesla dēļ, tāpēc pirms plūsmas kontroles vainošanas pārliecinieties, ka pavediens patiešām ir read iekšienē.

Pārbaudiet partnera sūtīšanas rindu un logu, ko tas pēdējo reizi redzēja. Ja partneris aiztur datus tāpēc, ka jūsu logs ir nulle, labojums ir jūsu ACK ceļā, nevis TUN lasījumā.

ENOBUFS ir izmēra problēma, nevis bufera trūkums

Rakstīšana, kas TUN saskarnē atgriež ENOBUFS, parasti noraida paketes garumu. Saskarnei ir MTU, lielāku paketi nevar ievietot rindā, un tās pašas paketes atkārtošana katru reizi neizdodas tāpat. Šī determinētība ir pazīme. Īsts bufera trūkums izzūd, kad spiediens samazinās, savukārt izmēra noraidīšanai nav svarīgi, cik ilgi jūs gaidāt.

TCP ir mehānisms tieši šim nolūkam, un tas ir solis, ko cilvēki izlaiž: MSS ierobežojums. Kad lietotāja telpā sintezējat segmentus, jūs izvēlaties lietderīgās kravas lielumu, un tā ņemšana no vietējās saskarnes MTU, nevis tuneļa MTU, izdod segmentus, ko tunelis nevar pārvadāt. Ierobežojiet līdz mazākajam no diviem. Ierobežojums attiecas tikai uz TCP, tāpēc pārāk lielu UDP datagrammu jūsu kodam ir jāsadala vai jāatmet.

Atkļūdošanas laikā reģistrējiet katras rakstītās paketes garumu. Garums, kas neizdodas, ir atbilde, un tas starp mēģinājumiem nemainīsies.

Trīs mērījumi, kas atdala gadījumus

Jums nav nepieciešams atkļūdotājs nevienai no abām atteicēm. Trīs novērojumi ir pietiekami, lai virzītu sevi uz pareizo sadaļu, un tie aizņem mazāk laika nekā pārbūve.

What you seeWhere to look
Reader parked, peer send queue empty, last advertised window zeroWindow updates in your ACK path
Write fails on one length and succeeds on a smaller oneMSS clamp and tunnel MTU
Both directions look fine, app still sees no dataProtected socket and routing loop

Ja trešā rinda sakrīt, pati cilpa ir kārtībā, un problēma ir tur, kur tunelis to nevar redzēt: neaizsargāta transporta ligzda, kas nes jūsu paša VPN satiksmi atpakaļ tunelī, un tas parasti izpaužas kā savienojums, kas izdodas un pēc tam neko nepiegādā.

Salabojiet cauruļvadu, no kura atkarīgi abi ceļi

Neviens simptoms nav vērts dzīties, kamēr saskarne nav pareizi uzbūvēta. Svarīgie builder izsaukumi ir adrese, maršruts, MTU un piekrišana, šajā secībā:

Builder()
  .addAddress(10.8.0.2, 32)
  .addRoute(0.0.0.0, 0)
  .setMtu(1400)
  .establish()

Iestatiet MTU uz tuneļa reālo vērtību, nevis atstājiet to tādu, kādu izmantoja piemērs. Viss, ko vēlāk rakstīsiet, ir ierobežots ar šo skaitli, un neatbilstība starp iestatīto MTU un MSS, līdz kuram ierobežojat, ir visizplatītākais veids, kā pēc labojuma atkal ieviest rakstīšanas atteici. Pēc tam aizsargājiet ligzdu, kas nes satiksmi uz pašu VPN serveri. Bez protect šīs paketes tiek maršrutētas atpakaļ jūsu pašu tunelī, un savienojums nekad netiek pabeigts, kas izskatās kā iestrēdzis lasījums, bet ir maršrutēšanas cilpa.

Piekrišanu nevar apiet. Serviss, kas palaists bez prepare atgriezta null, nesaņem saskarni, un establish atgriež null, nevis met, tāpēc pārbaudiet deskriptoru pirms cilpas sākšanas. VpnService atsauce ir vieta, kur apstiprināt builder līgumu, nevis kopēt piemēru.

Pārbaudiet vienu virzienu vienlaikus

Pirms TCP aizskaršanas nosūtiet UDP atbalsi caur tuneli un vērojiet pakešu garumus. Pēc tam atveriet rokas satvērienu un apstipriniet, ka segmenti paliek zem jūsu aprēķinātā MSS. Skaitiet paketes, nevis savienojumus, lai iestrēgums parādītos kā robs skaitītājā, nevis kā iekārusies ligzda. Ja lasījumi apstājas pēc rakstīšanas uzliesmojuma, aizdomās turamais ir logs; ja rakstīšana neizdodas uzreiz, tas ir garums.

Pēc tam pārstartējiet ierīci un atkārtojiet vienreiz, jo VpnService, kas darbojas tikai līdz pirmajai tīkla maiņai, ir maršrutēšanas, nevis plūsmas kontroles problēma.

Saistītie raksti