ഒരേ VpnService ലൂപ്പിൽ രണ്ട് ലക്ഷണങ്ങൾ പ്രത്യക്ഷപ്പെടുന്നു, രണ്ടിനെയും ഒരേ കാര്യം കുറ്റപ്പെടുത്തുന്നു: ഒരിക്കലും മടങ്ങാത്ത വായനക്കാരൻ, ENOBUFS-നൊപ്പം പരാജയപ്പെടുന്ന എഴുത്ത്. ഇവ ഒരു ബഗ്ഗിന്റെ ഭേദങ്ങളല്ല. കുടുങ്ങിയ വായന പിയറുമായുള്ള ഫ്ലോ കൺട്രോളിനെക്കുറിച്ചുള്ള അഭിപ്രായവ്യത്യാസമാണ്; പരാജയപ്പെട്ട എഴുത്ത് ഇന്റർഫേസ് സ്വീകരിക്കാത്ത പാക്കറ്റാണ്. ഇവയെ ഒരു പ്രശ്നമായി കണ്ടാൽ, ഒരിക്കലും ഉൾപ്പെടാത്ത ബഫറുകൾ ട്യൂൺ ചെയ്യുന്നതിൽ ഒരു ദിവസം ചെലവഴിക്കും. താഴെയുള്ള വിഭജനമാണ് ലൂപ്പിന്റെ ഏത് പകുതി ആദ്യം അളക്കണമെന്ന് ഞാൻ തീരുമാനിക്കുന്ന രീതി.

ഒരു ലൂപ്പ്, രണ്ട് സ്വതന്ത്ര പരാജയ പോയിന്റുകൾ

നിങ്ങളുടെ സേവനം TUN ഫയൽ ഡിസ്ക്രിപ്റ്ററിൽ നിന്ന് ഒരു IP പാക്കറ്റ് വായിക്കുന്നു, അത് പരിശോധിക്കുന്നു, അതേ ഡിസ്ക്രിപ്റ്ററിലേക്ക് മറുപടി എഴുതുന്നു. ആ പാതയിൽ തകരുന്നതെല്ലാം ആ രണ്ട് കോളുകളിൽ ഒന്നിൽ പ്രത്യക്ഷപ്പെടുന്നു, അതുകൊണ്ടാണ് രണ്ടിനെയും ടണൽ തകർന്നതായി റിപ്പോർട്ട് ചെയ്യുന്നത്. കോളുകൾക്ക് വ്യത്യസ്ത കരാറുകളുണ്ട്. വായന കെർണൽ നിങ്ങൾക്ക് പാക്കറ്റ് നൽകാൻ കാത്തിരിക്കുന്നു, എഴുത്ത് കെർണലിന് നിരസിക്കാൻ അവകാശമുള്ള പാക്കറ്റ് നൽകുന്നു.

വായനകൾ ചിന്തിക്കാൻ എളുപ്പമുള്ള പകുതിയാണ്. ഒന്നും തിരികെ നൽകാത്ത വായന ഒരിക്കലും വരാത്ത ട്രാഫിക്കിനായി കാത്തിരിക്കുന്നു, അല്ലെങ്കിൽ പിയർ അയക്കുന്നത് നിർത്തിയതിനാൽ കാത്തിരിക്കുന്നു.

കുടുങ്ങിയ വായന ഫ്ലോ കൺട്രോളിലെ അഭിപ്രായവ്യത്യാസമാണ്

TUN ഉപകരണം വായിക്കുന്നത് പാക്കറ്റ് ലഭ്യമാകുന്നതുവരെ ബ്ലോക്ക് ചെയ്യുന്നു. അത് രൂപകൽപ്പന ചെയ്ത സ്വഭാവമാണ്, അതുകൊണ്ടാണ് read-നുള്ളിൽ നിൽക്കുന്ന ത്രെഡ് നിഷ്ക്രിയ ലിങ്കിൽ സാധാരണമായി തോന്നുന്നത്. നിങ്ങളുടെ സ്വന്തം TCP സ്റ്റാക്ക് പ്രാദേശിക ആപ്പിൽ നിന്ന് ഡാറ്റ സ്വീകരിക്കുന്നത് തുടരുമ്പോൾ വിദൂര പിയറിന് കൂടുതൽ അയക്കാൻ മതിയായ വിൻഡോ പ്രഖ്യാപിക്കാത്തപ്പോൾ അത് ഹാംഗ് ആകുന്നു. പിയർ നിങ്ങൾ പ്രഖ്യാപിച്ച വിൻഡോ നിറയ്ക്കുന്നു, ACK-നും വിൻഡോ അപ്ഡേറ്റിനും കാത്തിരിക്കുന്നു, പിന്നെ നിർത്തുന്നു. അപ്പോൾ നിങ്ങളുടെ വായനക്കാരന് തിരികെ നൽകാൻ ഒന്നുമില്ല, ആപ്പ് തുറന്നതും നിശബ്ദവുമായ ഒരു കണക്ഷൻ കാണുന്നു.

സാധാരണ കാരണങ്ങൾ പ്രഖ്യാപിത വിൻഡോ ട്രാക്ക് ചെയ്യാതെ സോക്കറ്റിൽ എഴുതുന്ന സ്റ്റാക്കും, തന്റെ ബഫർ കാലിയാക്കിയ ശേഷം വിൻഡോ അപ്ഡേറ്റ് അയക്കാൻ മറക്കുന്ന സ്റ്റാക്കുമാണ്. പുറത്തുനിന്ന് രണ്ടും ഒരേപോലെ തോന്നും: ബൈറ്റുകൾ പുറത്തുപോകുന്നു, ഒന്നും തിരികെ വരുന്നില്ല, പിശക് ഉയരുന്നില്ല. പാഴ്സിംഗ്, DNS റെസല്യൂഷൻ, ഡിസ്ക് I/O എന്നിവയിൽ വായന ത്രെഡ് ബ്ലോക്ക് ചെയ്യുന്നത് ബന്ധമില്ലാത്ത കാരണത്താൽ അതേ രൂപത്തിലുള്ള ലക്ഷണം ഉണ്ടാക്കുന്നു, അതിനാൽ ഫ്ലോ കൺട്രോളിനെ കുറ്റപ്പെടുത്തുന്നതിന് മുമ്പ് ത്രെഡ് യഥാർത്ഥത്തിൽ read-നുള്ളിലാണെന്ന് ഉറപ്പാക്കുക.

പിയറിന്റെ അയക്കൽ ക്യൂവും അത് അവസാനം കണ്ട വിൻഡോയും പരിശോധിക്കുക. നിങ്ങളുടെ വിൻഡോ പൂജ്യമായതിനാൽ പിയർ ഡാറ്റ പിടിച്ചുവയ്ക്കുന്നുണ്ടെങ്കിൽ, തിരുത്ത് നിങ്ങളുടെ ACK പാതയിലാണ്, TUN വായനയിലല്ല.

ENOBUFS വലിപ്പത്തിന്റെ പ്രശ്നമാണ്, ബഫർ കുറവല്ല

TUN ഇന്റർഫേസിൽ ENOBUFS തിരികെ നൽകുന്ന എഴുത്ത് സാധാരണയായി പാക്കറ്റ് നീളം നിരസിക്കുന്നു. ഇന്റർഫേസിന് ഒരു MTU ഉണ്ട്, അതിനേക്കാൾ വലിയ പാക്കറ്റ് ക്യൂവിൽ ചേർക്കാൻ കഴിയില്ല, അതേ പാക്കറ്റ് വീണ്ടും ശ്രമിച്ചാൽ ഓരോ തവണയും അതേപോലെ പരാജയപ്പെടുന്നു. ആ നിർണ്ണായകതയാണ് സൂചന. യഥാർത്ഥ ബഫർ കുറവ് സമ്മർദ്ദം കുറയുമ്പോൾ മാറുന്നു, എന്നാൽ വലിപ്പനിരസനം നിങ്ങൾ എത്ര കാത്തിരുന്നാലും കാര്യമാക്കുന്നില്ല.

TCP-യ്ക്ക് ഇതിനായി തന്നെ ഒരു സംവിധാനമുണ്ട്, അതാണ് ആളുകൾ ഒഴിവാക്കുന്ന ഘട്ടം: MSS ക്ലാമ്പ്. ഉപയോക്തൃ സ്ഥലത്ത് സെഗ്മെന്റുകൾ സംശ്ലേഷിക്കുമ്പോൾ പേലോഡ് വലിപ്പം നിങ്ങളാണ് തിരഞ്ഞെടുക്കുന്നത്, അത് ടണലിന്റെ MTU-വിന് പകരം പ്രാദേശിക ഇന്റർഫേസിന്റെ MTU-വിൽ നിന്ന് എടുക്കുന്നത് ടണലിന് വഹിക്കാനാകാത്ത സെഗ്മെന്റുകൾ പുറപ്പെടുവിക്കുന്നു. രണ്ടിൽ ചെറുതിലേക്ക് പരിമിതപ്പെടുത്തുക. ക്ലാമ്പ് TCP-യെ മാത്രം ഉൾക്കൊള്ളുന്നു, അതിനാൽ വളരെ വലിയ UDP ഡാറ്റാഗ്രാം നിങ്ങളുടെ കോഡ് ശകലം ചെയ്യുകയോ ഒഴിവാക്കുകയോ വേണം.

ഡീബഗ് ചെയ്യുമ്പോൾ നിങ്ങൾ എഴുതുന്ന ഓരോ പാക്കറ്റിന്റെയും നീളം ലോഗ് ചെയ്യുക. പരാജയപ്പെടുന്ന നീളമാണ് ഉത്തരം, അത് ശ്രമങ്ങൾക്കിടയിൽ മാറില്ല.

കേസുകളെ വേർതിരിക്കുന്ന മൂന്ന് അളവുകൾ

രണ്ട് പരാജയങ്ങൾക്കും നിങ്ങൾക്ക് ഡീബഗർ ആവശ്യമില്ല. ശരിയായ വിഭാഗത്തിലേക്ക് നയിക്കാൻ മൂന്ന് നിരീക്ഷണങ്ങൾ മതി, അവ പുനർനിർമ്മാണത്തേക്കാൾ കുറഞ്ഞ സമയമെടുക്കുന്നു.

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

മൂന്നാമത്തെ വരി യോജിക്കുന്നുവെങ്കിൽ, ലൂപ്പ് തന്നെ കുഴപ്പമില്ല, പ്രശ്നം ടണലിന് കാണാൻ കഴിയാത്തിടത്താണ്: നിങ്ങളുടെ സ്വന്തം VPN ട്രാഫിക് ടണലിലേക്ക് തിരികെ കൊണ്ടുപോകുന്ന സംരക്ഷിക്കപ്പെടാത്ത ട്രാൻസ്പോർട്ട് സോക്കറ്റ്, ഇത് സാധാരണയായി വിജയിച്ച ശേഷം ഒന്നും എത്തിക്കാത്ത കണക്ഷനായി കാണപ്പെടുന്നു.

രണ്ട് പാതകളും ആശ്രയിക്കുന്ന പ്ലംബിംഗ് നന്നാക്കുക

ഇന്റർഫേസ് ശരിയായി നിർമ്മിക്കുന്നതുവരെ ഒരു ലക്ഷണവും പിന്തുടരാൻ യോഗ്യമല്ല. പ്രധാന builder കോളുകൾ വിലാസം, റൂട്ട്, MTU, സമ്മതം എന്നിവയാണ്, ആ ക്രമത്തിൽ:

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

MTU സാമ്പിൾ ഉപയോഗിച്ച മൂല്യത്തിൽ വിടാതെ ടണലിന്റെ യഥാർത്ഥ മൂല്യത്തിലേക്ക് സെറ്റ് ചെയ്യുക. പിന്നീട് നിങ്ങൾ എഴുതുന്നതെല്ലാം ആ സംഖ്യയാൽ പരിമിതമാണ്, നിങ്ങൾ സെറ്റ് ചെയ്യുന്ന MTU-വും നിങ്ങൾ പരിമിതപ്പെടുത്തുന്ന MSS-ഉം തമ്മിലുള്ള പൊരുത്തക്കേടാണ് തിരുത്തലിനുശേഷം എഴുത്ത് പരാജയം വീണ്ടും കൊണ്ടുവരാനുള്ള ഏറ്റവും സാധാരണ മാർഗം. പിന്നെ VPN സർവറിലേക്കുള്ള ട്രാഫിക് വഹിക്കുന്ന സോക്കറ്റ് സംരക്ഷിക്കുക. protect ഇല്ലാതെ ആ പാക്കറ്റുകൾ നിങ്ങളുടെ സ്വന്തം ടണലിലേക്ക് തിരികെ റൂട്ട് ചെയ്യപ്പെടുന്നു, കണക്ഷൻ ഒരിക്കലും പൂർത്തിയാകുന്നില്ല, അത് കുടുങ്ങിയ വായനയായി തോന്നാം പക്ഷേ റൂട്ടിംഗ് ലൂപ്പാണ്.

സമ്മതം ഒഴിവാക്കാൻ കഴിയില്ല. prepare null തിരികെ നൽകാതെ ആരംഭിച്ച സേവനത്തിന് ഇന്റർഫേസ് ലഭിക്കുന്നില്ല, establish എറിയുന്നതിന് പകരം null തിരികെ നൽകുന്നു, അതിനാൽ ലൂപ്പ് ആരംഭിക്കുന്നതിന് മുമ്പ് ഡിസ്ക്രിപ്റ്റർ പരിശോധിക്കുക. VpnService റഫറൻസ് സാമ്പിൾ പകർത്തുന്നതിന് പകരം builder കരാർ സ്ഥിരീകരിക്കാനുള്ള സ്ഥലമാണ്.

ഒരു സമയം ഒരു ദിശ പരിശോധിക്കുക

TCP സ്പർശിക്കുന്നതിന് മുമ്പ് ടണലിലൂടെ UDP എക്കോ അയച്ച് പാക്കറ്റ് നീളങ്ങൾ നിരീക്ഷിക്കുക. പിന്നെ ഒരു ഹാൻഡ്ഷേക്ക് തുറന്ന് സെഗ്മെന്റുകൾ നിങ്ങൾ കണക്കാക്കിയ MSS-ന് താഴെ നിൽക്കുന്നുവെന്ന് സ്ഥിരീകരിക്കുക. കണക്ഷനുകൾക്ക് പകരം പാക്കറ്റുകൾ എണ്ണുക, അപ്പോൾ തടസ്സം തൂങ്ങിയ സോക്കറ്റിന് പകരം കൗണ്ടറിലെ വിടവായി കാണാം. എഴുത്തുകളുടെ പൊട്ടിത്തെറിക്ക് ശേഷം വായന നിലയ്ക്കുന്നുവെങ്കിൽ, വിൻഡോയാണ് സംശയിക്കേണ്ടത്; എഴുത്തുകൾ ഉടൻ പരാജയപ്പെട്ടാൽ, നീളമാണ്.

പിന്നെ ഉപകരണം റീബൂട്ട് ചെയ്ത് ഒരു തവണ ആവർത്തിക്കുക, കാരണം ആദ്യ നെറ്റ്വർക്ക് മാറ്റം വരെ മാത്രം പ്രവർത്തിക്കുന്ന VpnService ഫ്ലോ കൺട്രോളിന്റെയല്ല, റൂട്ടിംഗിന്റെ പ്രശ്നമാണ്.

അനുബന്ധ ലേഖനങ്ങൾ