Beirniadaeth o brotocol a dulliau sefydliadol Telegram. Rhan 1, technegol: profiad o ysgrifennu cleient o'r dechrau - TL, MT

Yn ddiweddar, mae swyddi am ba mor dda yw Telegram, pa mor wych a phrofiadol yw'r brodyr Durov wrth adeiladu systemau rhwydwaith, ac ati wedi dechrau ymddangos yn amlach ar Habré. Ar yr un pryd, ychydig iawn o bobl sydd wedi ymgolli mewn gwirionedd yn y ddyfais dechnegol - ar y mwyaf, maent yn defnyddio API Bot eithaf syml (ac yn eithaf gwahanol i MTProto) yn seiliedig ar JSON, ac fel arfer dim ond derbyn ar ffydd yr holl glodydd a PR sy'n troi o amgylch y negesydd. Bron i flwyddyn a hanner yn ôl, dechreuodd fy nghydweithiwr yn NGO Eshelon Vasily (yn anffodus, cafodd ei gyfrif ar Habré ei ddileu ynghyd â'r drafft) ysgrifennu ei gleient Telegram ei hun o'r dechrau yn Perl, ac yn ddiweddarach ymunodd awdur y llinellau hyn. Pam Perl, bydd rhai yn gofyn ar unwaith? Oherwydd bod prosiectau o'r fath eisoes yn bodoli mewn ieithoedd eraill, a dweud y gwir, nid dyma'r pwynt, gallai fod unrhyw iaith arall lle nad oes llyfrgell parod, ac yn ol hyn rhaid i'r awdwr fyned yr holl ffordd o'r dechrau. Ar ben hynny, mae cryptograffeg yn fater o ymddiriedaeth, ond gwiriwch. Gyda chynnyrch sydd wedi'i anelu at ddiogelwch, ni allwch ddibynnu ar lyfrgell barod gan y gwneuthurwr ac ymddiried ynddo'n ddall (fodd bynnag, mae hwn yn bwnc ar gyfer yr ail ran). Ar hyn o bryd, mae'r llyfrgell yn gweithio'n eithaf da ar y lefel “gyfartaledd” (yn caniatáu ichi wneud unrhyw geisiadau API).

Fodd bynnag, ni fydd llawer o cryptograffeg na mathemateg yn y gyfres hon o bostiadau. Ond bydd llawer o fanylion technegol a baglau pensaernïol eraill (hefyd yn ddefnyddiol i'r rhai na fyddant yn ysgrifennu o'r dechrau, ond a fydd yn defnyddio'r llyfrgell mewn unrhyw iaith). Felly, y prif nod oedd ceisio gweithredu'r cleient o'r dechrau yn ôl dogfennaeth swyddogol. Hynny yw, gadewch i ni dybio bod cod ffynhonnell cleientiaid swyddogol ar gau (eto, yn yr ail ran byddwn yn ymdrin yn fanylach â phwnc y ffaith bod hyn yn wir mae'n digwydd felly), ond, fel yn yr hen ddyddiau, er enghraifft, mae safon fel RFC - a yw'n bosibl ysgrifennu cleient yn ôl y fanyleb yn unig, "heb edrych" ar y cod ffynhonnell, boed yn swyddogol (Telegram Desktop, symudol), neu Telethon answyddogol?

Gemau:

Dogfennaeth... mae'n bodoli, iawn? Ydy e'n wir?..

Dechreuwyd casglu darnau o nodiadau ar gyfer yr erthygl hon yr haf diwethaf. Yr holl amser hwn ar y wefan swyddogol https://core.telegram.org Roedd y ddogfennaeth ar Haen 23, h.y. yn sownd yn rhywle yn 2014 (cofiwch, nid oedd hyd yn oed sianeli yn ôl bryd hynny?). Wrth gwrs, mewn theori, dylai hyn fod wedi caniatáu inni weithredu cleient ag ymarferoldeb bryd hynny yn 2014. Ond hyd yn oed yn y cyflwr hwn, roedd y ddogfennaeth, yn gyntaf, yn anghyflawn, ac yn ail, mewn mannau roedd yn gwrth-ddweud ei hun. Ychydig dros fis yn ôl, ym mis Medi 2019, yr oedd ar hap Darganfuwyd bod yna ddiweddariad mawr o'r ddogfennaeth ar y safle, ar gyfer yr Haen 105 cwbl ddiweddar, gyda nodyn nawr bod angen darllen popeth eto. Yn wir, adolygwyd llawer o erthyglau, ond arhosodd llawer heb eu newid. Felly, wrth ddarllen y feirniadaeth isod am y ddogfennaeth, dylech gadw mewn cof nad yw rhai o'r pethau hyn bellach yn berthnasol, ond mae rhai yn dal yn eithaf. Wedi'r cyfan, nid dim ond amser hir yw 5 mlynedd yn y byd modern, ond hefyd iawn llawer o. Ers yr amseroedd hynny (yn enwedig os nad ydych yn ystyried y safleoedd geochat sydd wedi'u taflu a'u hadfywio ers hynny), mae nifer y dulliau API yn y cynllun wedi cynyddu o gant i fwy na dau gant a hanner!

Ble i ddechrau fel awdur ifanc?

Nid oes ots a ydych chi'n ysgrifennu o'r dechrau neu'n defnyddio, er enghraifft, llyfrgelloedd parod fel Telethon ar gyfer Python neu Madeline ar gyfer PHP, mewn unrhyw achos, bydd angen yn gyntaf cofrestrwch eich cais - cael paramedrau api_id и api_hash (mae'r rhai sydd wedi gweithio gyda'r API VKontakte yn deall ar unwaith) y bydd y gweinydd yn nodi'r cais trwyddo. hwn rhaid ei wneud am resymau cyfreithiol, ond byddwn yn siarad mwy am pam na all awduron llyfrgell ei gyhoeddi yn yr ail ran. Efallai eich bod yn fodlon â gwerthoedd y prawf, er eu bod yn gyfyngedig iawn - y ffaith yw y gallwch chi gofrestru nawr Dim ond un app, felly peidiwch â rhuthro i mewn iddo.

Nawr, o safbwynt technegol, dylai fod gennym ddiddordeb yn y ffaith y dylem dderbyn hysbysiadau gan Telegram ar ôl cofrestru am ddiweddariadau i ddogfennaeth, protocol, ac ati. Hynny yw, gellid tybio bod y safle gyda'r dociau wedi'i adael yn syml ac yn parhau i weithio'n benodol gyda'r rhai a ddechreuodd wneud cleientiaid, oherwydd mae'n haws. Ond na, ni sylwyd ar ddim o'r fath, ni ddaeth unrhyw wybodaeth.

Ac os ydych chi'n ysgrifennu o'r dechrau, yna mae defnyddio'r paramedrau a gafwyd mewn gwirionedd yn dal i fod ymhell i ffwrdd. Er https://core.telegram.org/ ac yn sôn amdanynt yn Dechrau Arni yn gyntaf oll, mewn gwirionedd, yn gyntaf bydd yn rhaid ichi weithredu Protocol MTProto — ond pe credech gosodiad yn ôl y model OSI ar ddiwedd y dudalen am ddisgrifiad cyffredinol o'r protocol, yna mae'n gwbl ofer.

Mewn gwirionedd, cyn ac ar ôl MTProto, ar sawl lefel ar unwaith (fel y dywed rhwydwaithwyr tramor sy'n gweithio yn y cnewyllyn OS, torri haen), bydd pwnc mawr, poenus ac ofnadwy yn rhwystro ...

Cyfresoli deuaidd: TL (Math o Iaith) a'i gynllun, a haenau, a llawer o eiriau brawychus eraill

Y pwnc hwn, mewn gwirionedd, yw'r allwedd i broblemau Telegram. A bydd llawer o eiriau ofnadwy os ceisiwch ymchwilio iddo.

Felly, dyma'r diagram. Os daw'r gair hwn i'ch meddwl, dywedwch, Sgema JSON, Roeddech chi'n meddwl yn gywir. Yr un yw'r nod: rhywfaint o iaith i ddisgrifio set bosibl o ddata a drosglwyddir. Dyma lle mae'r tebygrwydd yn dod i ben. Os o'r dudalen Protocol MTProto, neu o goeden ffynhonnell y cleient swyddogol, byddwn yn ceisio agor rhywfaint o sgema, byddwn yn gweld rhywbeth fel:

int ? = Int;
long ? = Long;
double ? = Double;
string ? = String;

vector#1cb5c415 {t:Type} # [ t ] = Vector t;

rpc_error#2144ca19 error_code:int error_message:string = RpcError;

rpc_answer_unknown#5e2ad36e = RpcDropAnswer;
rpc_answer_dropped_running#cd78e586 = RpcDropAnswer;
rpc_answer_dropped#a43ad8b7 msg_id:long seq_no:int bytes:int = RpcDropAnswer;

msg_container#73f1f8dc messages:vector<%Message> = MessageContainer;

---functions---

set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:bytes = Set_client_DH_params_answer;

ping#7abe77ec ping_id:long = Pong;
ping_delay_disconnect#f3427b8c ping_id:long disconnect_delay:int = Pong;

invokeAfterMsg#cb9f372d msg_id:long query:!X = X;
invokeAfterMsgs#3dc4b4f0 msg_ids:Vector<long> query:!X = X;

account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User;
account.sendChangePhoneCode#8e57deb flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode;

Bydd person sy'n gweld hyn am y tro cyntaf yn reddfol yn gallu adnabod dim ond rhan o'r hyn sydd wedi'i ysgrifennu - wel, mae'n debyg mai strwythurau yw'r rhain (er ble mae'r enw, ar y chwith neu ar y dde?), mae caeau ynddynt, ac ar ôl hynny mae math yn dilyn ar ôl colon... yn ôl pob tebyg. Yma mewn cromfachau ongl mae'n debyg bod templedi fel yn C++ (mewn gwirionedd, ddim mewn gwirionedd). A beth mae'r symbolau eraill i gyd yn ei olygu, marciau cwestiwn, ebychnodau, canrannau, hashnodau (ac yn amlwg maen nhw'n golygu gwahanol bethau mewn gwahanol leoedd), weithiau'n bresennol ac weithiau ddim, rhifau hecsadegol - ac yn bwysicaf oll, sut i ddod o hyn cywir (na fydd yn cael ei wrthod gan y gweinydd) ffrwd beit? Bydd yn rhaid i chi ddarllen y ddogfennaeth (oes, mae yna ddolenni i'r sgema yn fersiwn JSON gerllaw - ond nid yw hynny'n ei gwneud hi'n gliriach).

Agorwch y dudalen Cyfresi Data Deuaidd a phlymio i fyd hudol madarch a mathemateg arwahanol, rhywbeth tebyg i fatan yn y 4edd flwyddyn. Wyddor, math, gwerth, cyfunwr, cyfunwr swyddogaethol, ffurf arferol, math cyfansawdd, math polymorffig ... a dim ond y dudalen gyntaf yw hynny i gyd! Mae nesaf yn aros amdanoch chi Iaith TL, nad yw, er ei fod eisoes yn cynnwys enghraifft o gais ac ymateb dibwys, yn rhoi ateb o gwbl i achosion mwy nodweddiadol, sy’n golygu y bydd yn rhaid ichi gamu drwy ailadrodd mathemateg a gyfieithwyd o’r Rwsieg i’r Saesneg ar wyth arall sydd wedi’u mewnosod. tudalennau!

Bydd darllenwyr sy'n gyfarwydd ag ieithoedd swyddogaethol a chasgliad teip awtomatig, wrth gwrs, yn gweld yr iaith ddisgrifio yn yr iaith hon, hyd yn oed o'r enghraifft, yn llawer mwy cyfarwydd, a gallant ddweud nad yw hyn mewn gwirionedd yn ddrwg mewn egwyddor. Y gwrthwynebiadau i hyn yw:

  • ie, nod swnio'n dda, ond gwaetha'r modd, mae hi heb ei gyflawni
  • Mae addysg ym mhrifysgolion Rwsia yn amrywio hyd yn oed ymhlith arbenigeddau TG - nid yw pawb wedi dilyn y cwrs cyfatebol
  • Yn olaf, fel y gwelwn, yn ymarferol y mae ddim yn ofynnol, gan mai dim ond is-set gyfyngedig o hyd yn oed y TL a ddisgrifiwyd a ddefnyddir

Fel y dywedwyd LeonNerd ar y sianel #perl yn rhwydwaith FreeNode IRC, a geisiodd weithredu giât o Telegram i Matrix (mae cyfieithiad o'r dyfyniad yn anghywir o'r cof):

Mae'n teimlo fel pe bai rhywun wedi'i gyflwyno i theori teipio am y tro cyntaf, wedi cyffroi, ac wedi dechrau ceisio chwarae o gwmpas ag ef, heb ofalu a oedd ei angen yn ymarferol.

Weld drosoch eich hun, os nad yw'r angen am fathau noeth (int, hir, ac ati) fel rhywbeth elfennol yn codi cwestiynau - yn y pen draw mae'n rhaid eu gweithredu â llaw - er enghraifft, gadewch i ni gymryd ymgais i ddeillio ohonynt fector. Hynny yw, mewn gwirionedd, arae, os byddwch yn galw y pethau canlyniadol wrth eu henwau priodol.

Ond cyn

Disgrifiad byr o is-set o gystrawen TL ar gyfer y rhai nad ydynt yn darllen y ddogfennaeth swyddogol

constructor = Type;
myVec ids:Vector<long> = Type;

fixed#abcdef34 id:int = Type2;

fixedVec set:Vector<Type2> = FixedVec;

constructorOne#crc32 field1:int = PolymorType;
constructorTwo#2crc32 field_a:long field_b:Type3 field_c:int = PolymorType;
constructorThree#deadcrc bit_flags_of_what_really_present:# optional_field4:bit_flags_of_what_really_present.1?Type = PolymorType;

an_id#12abcd34 id:int = Type3;
a_null#6789cdef = Type3;

Diffiniad bob amser yn dechrau lluniwr, ac ar ôl hynny yn ddewisol (yn ymarferol - bob amser) trwy'r symbol # rhaid iddynt fod yn CRC32 o'r llinyn disgrifiad normaleiddio o'r math hwn. Nesaf daw disgrifiad o'r meysydd; os ydynt yn bodoli, gall y math fod yn wag. Mae hyn i gyd yn gorffen gydag arwydd cyfartal, sef enw'r math y mae'r lluniwr hwn - hynny yw, mewn gwirionedd, yr isdeip - yn perthyn iddo. Mae'r dyn i'r dde o'r arwydd hafal yn polymorphic - hynny yw, gall sawl math penodol gyfateb iddo.

Os bydd y diffiniad yn digwydd ar ôl y llinell ---functions---, yna bydd y gystrawen yn aros yr un fath, ond bydd yr ystyr yn wahanol: bydd yr adeiladwr yn dod yn enw'r swyddogaeth RPC, bydd y meysydd yn dod yn baramedrau (wel, hynny yw, bydd yn aros yn union yr un strwythur a roddir, fel y disgrifir isod , yn syml, dyma fydd yr ystyr a neilltuwyd), a'r “math polymorphic” - math y canlyniad a ddychwelwyd. Yn wir, bydd yn parhau i fod yn amrymorffig - newydd ei ddiffinio yn yr adran ---types---, ond ni fydd yr adeiladwr hwn “yn cael ei ystyried”. Gorlwytho’r mathau o swyddogaethau a elwir yn ôl eu dadleuon, h.y. Am ryw reswm, ni ddarperir ar gyfer sawl swyddogaeth gyda'r un enw ond llofnodion gwahanol, fel yn C++, yn y TL.

Pam "adeiladwr" a "polymorffig" os nad yw'n OOP? Wel, mewn gwirionedd, bydd yn haws i rywun feddwl am hyn mewn termau OOP - math polymorffig fel dosbarth haniaethol, ac adeiladwyr yw ei ddosbarthiadau disgynyddion uniongyrchol, a final mewn terminoleg nifer o ieithoedd. Yn wir, wrth gwrs, yma yn unig tebygrwydd gyda dulliau gorlwytho adeiladwr go iawn mewn ieithoedd rhaglennu OO. Gan mai strwythurau data yn unig yw yma, nid oes unrhyw ddulliau (er bod y disgrifiad o swyddogaethau a dulliau ymhellach yn eithaf gallu creu dryswch yn y pen eu bod yn bodoli, ond mae hynny'n fater gwahanol) - gallwch chi feddwl am adeiladwr fel gwerth o sydd yn cael ei adeiladu teipiwch wrth ddarllen ffrwd beit.

Sut mae hyn yn digwydd? Mae'r dadserializer, sydd bob amser yn darllen 4 beit, yn gweld y gwerth 0xcrc32 - ac yn deall beth fydd yn digwydd nesaf field1 gyda math int, h.y. yn darllen yn union 4 beit, ar hwn y maes dros ben gyda'r math PolymorType darllen. Gwêl 0x2crc32 ac yn deall fod dau faes yn mhellach, yn gyntaf long, sy'n golygu ein bod yn darllen 8 beit. Ac yna eto math cymhleth, sy'n cael ei ddadgyfodi yn yr un modd. Er enghraifft, Type3 gellid ei ddatgan yn y gylched cyn gynted â dau adeiladwr, yn y drefn honno, yna rhaid iddynt gwrdd â'r naill neu'r llall 0x12abcd34, ac ar ôl hynny mae angen ichi ddarllen 4 beit arall intNeu 0x6789cdef, wedi hyny ni bydd dim. Unrhyw beth arall - mae angen i chi daflu eithriad. Beth bynnag, ar ôl hyn awn yn ôl i ddarllen 4 beit int caeau field_c в constructorTwo a chyda hyny terfynwn ddarllen ein PolymorType.

Yn olaf, os cewch eich dal 0xdeadcrc gyfer constructorThree, yna mae popeth yn dod yn fwy cymhleth. Ein maes cyntaf yw bit_flags_of_what_really_present gyda math # - mewn gwirionedd, dim ond alias ar gyfer y math yw hwn nat, sy'n golygu "rhif naturiol". Hynny yw, mewn gwirionedd, int heb ei lofnodi yw'r unig achos, gyda llaw, pan fo niferoedd heb eu harwyddo yn digwydd mewn cylchedau real. Felly, nesaf yw adeiladwaith gyda marc cwestiwn, sy'n golygu bod y maes hwn - bydd yn bresennol ar y wifren dim ond os yw'r darn cyfatebol wedi'i osod yn y maes y cyfeirir ato (yn fras fel gweithredwr teiran). Felly, gadewch i ni dybio bod y darn hwn wedi'i osod, sy'n golygu bod angen i ni ddarllen maes tebyg ymhellach Type, sydd yn ein hesiampl ni â 2 adeiladwr. Mae un yn wag (yn cynnwys y dynodwr yn unig), mae gan y llall faes ids gyda math ids:Vector<long>.

Efallai eich bod yn meddwl bod y ddau dempled a generig yn y manteision neu Java. Ond na. Bron. hwn yr unig achos o ddefnyddio cromfachau ongl mewn cylchedau go iawn, ac fe'i defnyddir YN UNIG ar gyfer Vector. Mewn ffrwd beit, bydd y rhain yn 4 CRC32 beit ar gyfer y math Vector ei hun, bob amser yr un fath, yna 4 beit - nifer yr elfennau arae, ac yna'r elfennau hyn eu hunain.

Ychwanegwch at hyn y ffaith bod cyfresoli bob amser yn digwydd mewn geiriau 4 beit, mae pob math yn lluosrifau ohono - disgrifir y mathau adeiledig hefyd bytes и string gyda chyfresoli â llaw o'r hyd a'r aliniad hwn gan 4 - wel, mae'n ymddangos ei fod yn swnio'n normal a hyd yn oed yn gymharol effeithiol? Er bod TL yn cael ei honni i fod yn serialization deuaidd effeithiol, i uffern gyda nhw, gydag ehangu dim ond am unrhyw beth, hyd yn oed gwerthoedd Boole a llinynnau un-cymeriad i 4 bytes, bydd JSON yn dal i fod yn llawer mwy trwchus? Edrychwch, gall hyd yn oed meysydd diangen gael eu hanwybyddu gan faneri bit, mae popeth yn eithaf da, a hyd yn oed yn estynadwy ar gyfer y dyfodol, felly beth am ychwanegu meysydd dewisol newydd at yr adeiladwr yn nes ymlaen?..

Ond na, os nad ydych yn darllen fy nisgrifiad byr, ond y ddogfennaeth lawn, ac yn meddwl am y gweithredu. Yn gyntaf, cyfrifir CRC32 y llunydd yn unol â llinell normaleiddio disgrifiad testun y cynllun (tynnwch ofod gwyn ychwanegol, ac ati) - felly os ychwanegir maes newydd, bydd y llinell disgrifiad math yn newid, ac felly ei CRC32 a , o ganlyniad, cyfresoli. A beth fyddai'r hen gleient yn ei wneud pe bai'n derbyn cae gyda fflagiau newydd wedi'u gosod, ac nad yw'n gwybod beth i'w wneud â nhw nesaf? ...

Yn ail, gadewch i ni gofio CRC32, a ddefnyddir yma yn y bôn fel swyddogaethau hash i benderfynu'n unigryw pa fath sy'n cael ei (dad)gyfresu. Yma rydym yn wynebu problem gwrthdrawiadau - a na, nid yw'r tebygolrwydd yn un mewn 232, ond yn llawer mwy. Pwy a gofiodd fod CRC32 wedi'i gynllunio i ganfod (a chywiro) gwallau yn y sianel gyfathrebu, ac yn unol â hynny yn gwella'r eiddo hyn ar draul eraill? Er enghraifft, nid yw'n poeni am aildrefnu beit: os ydych chi'n cyfrifo CRC32 o ddwy linell, yn yr ail fe fyddwch chi'n cyfnewid y 4 beit cyntaf gyda'r 4 beit nesaf - bydd yr un peth. Pan fydd ein mewnbwn yn llinynnau testun o'r wyddor Ladin (ac ychydig o atalnodi), ac nad yw'r enwau hyn yn arbennig o hap, mae'r tebygolrwydd o ad-drefnu o'r fath yn cynyddu'n fawr.

Gyda llaw, pwy wiriodd beth oedd yno? a dweud y gwir CRC32? Roedd gan un o'r codau ffynhonnell cynnar (hyd yn oed cyn Waltman) swyddogaeth hash a oedd yn lluosi pob cymeriad â'r rhif 239, mor annwyl gan y bobl hyn, ha ha!

Yn olaf, iawn, rydym yn sylweddoli bod adeiladwyr gyda math maes Vector<int> и Vector<PolymorType> bydd ganddynt CRC32 gwahanol. Beth am berfformiad ar-lein? Ac o safbwynt damcaniaethol, a yw hyn yn dod yn rhan o'r math? Gadewch i ni ddweud ein bod yn pasio amrywiaeth o ddeg mil o rifau, wel gyda Vector<int> popeth yn glir, hyd a 40000 beit arall. Beth os hyn Vector<Type2>, sy'n cynnwys un maes yn unig int ac mae ar ei ben ei hun yn y math - a oes angen i ni ailadrodd 10000xabcdef0 34 o weithiau ac yna 4 beit int, neu y mae yr iaith yn abl i'w ANNIBYNU i ni o'r lluniwr fixedVec ac yn lle 80000 beit, trosglwyddo eto dim ond 40000?

Nid yw hwn yn gwestiwn damcaniaethol segur o gwbl - dychmygwch eich bod yn derbyn rhestr o ddefnyddwyr grŵp, y mae gan bob un ohonynt id, enw cyntaf, enw olaf - gall y gwahaniaeth yn y swm o ddata a drosglwyddir dros gysylltiad symudol fod yn sylweddol. Yn union effeithiolrwydd cyfresoli Telegram sy'n cael ei hysbysebu i ni.

Felly…

Fector, na chafodd ei ryddhau erioed

Os byddwch yn ceisio rhydio drwy'r tudalennau disgrifiad o combinators ac yn y blaen, byddwch yn gweld bod fector (a hyd yn oed matrics) yn ffurfiol yn ceisio cael ei allbwn drwy tuples o sawl tudalen. Ond yn y diwedd maen nhw'n anghofio, mae'r cam olaf yn cael ei hepgor, a rhoddir diffiniad o fector yn syml, nad yw wedi'i glymu eto i fath. Beth sy'n bod? Mewn ieithoedd rhaglennu, yn enwedig rhai swyddogaethol, mae'n eithaf nodweddiadol disgrifio'r strwythur yn ailadroddus - bydd y casglwr gyda'i werthusiad diog yn deall ac yn gwneud popeth ei hun. Mewn iaith cyfresoli data yr hyn sydd ei angen yw EFFEITHLONRWYDD: mae'n ddigon i ddisgrifio'n syml список, h.y. strwythur dwy elfen - mae'r cyntaf yn elfen ddata, yr ail yw'r un strwythur ei hun neu le gwag ar gyfer y gynffon (pecyn (cons) yn Lisp). Ond bydd hyn yn amlwg yn gofyn yr un elfen yn gwario 4 beit ychwanegol (CRC32 yn achos TL) i ddisgrifio ei fath. Gellir disgrifio arae yn hawdd hefyd maint sefydlog, ond yn achos amrywiaeth o hyd anhysbys ymlaen llaw, rydym yn torri i ffwrdd.

Felly, gan nad yw TL yn caniatáu allbynnu fector, roedd yn rhaid ei ychwanegu ar yr ochr. Yn y pen draw mae’r ddogfennaeth yn dweud:

Mae cyfresoli bob amser yn defnyddio'r un “fector” llunydd (const 0x1cb5c415 = crc32 ("fector t: Math # [ t ] = Fector t") nad yw'n dibynnu ar werth penodol y newidyn math t.

Nid yw gwerth y paramedr dewisol t yn ymwneud â'r cyfresoli gan ei fod yn deillio o'r math o ganlyniad (sydd bob amser yn hysbys cyn dad-gyfresoli).

Cymerwch olwg agosach: vector {t:Type} # [ t ] = Vector t - ond unman Nid yw'r diffiniad hwn ei hun yn dweud bod yn rhaid i'r rhif cyntaf fod yn hafal i hyd y fector! Ac nid yw'n dod o unrhyw le. Mae hwn yn anrheg y mae angen ei gadw mewn cof a'i weithredu â'ch dwylo. Mewn man arall, mae'r ddogfennaeth hyd yn oed yn sôn yn onest nad yw'r math yn real:

Mae ffugdeip polymorphic Vector t yn “fath” y mae ei werth yn ddilyniant o werthoedd o unrhyw fath t, naill ai mewn bocs neu'n foel.

... ond nid yw'n canolbwyntio arno. Pan fyddwch chi, wedi blino cerdded trwy'r ymestyn mathemateg (efallai hyd yn oed yn hysbys i chi o gwrs prifysgol), yn penderfynu rhoi'r gorau iddi ac edrych ar sut i weithio gydag ef yn ymarferol, yr argraff a adawyd yn eich pen yw bod hyn yn Ddifrifol. Mathemateg yn greiddiol, roedd yn amlwg wedi'i ddyfeisio gan Cool People (dau fathemategydd - enillydd ACM), ac nid dim ond unrhyw un. Mae'r nod - dangos i ffwrdd - wedi'i gyflawni.

Gyda llaw, am y rhif. Gadewch inni eich atgoffa hynny # mae'n gyfystyr nat, rhif naturiol:

Mae yna ymadroddion math (math-expr) ac ymadroddion rhifol (nat-expr). Fodd bynnag, maent yn cael eu diffinio yn yr un modd.

type-expr ::= expr
nat-expr ::= expr

ond yn y gramadeg fe'u disgrifir yn yr un modd, h.y. Rhaid cofio'r gwahaniaeth hwn eto a'i roi ar waith â llaw.

Wel, ie, mathau o dempledi (vector<int>, vector<User>) â dynodwr cyffredin (#1cb5c415), h.y. os ydych yn gwybod bod yr alwad yn cael ei chyhoeddi fel

users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;

yna nid ydych bellach yn aros am fector yn unig, ond fector o ddefnyddwyr. Yn fwy manwl gywir, dylai aros - mewn cod go iawn, bydd gan bob elfen, os nad math moel, adeiladwr, ac mewn ffordd dda wrth weithredu byddai angen gwirio - ond fe'n hanfonwyd yn union ym mhob elfen o'r fector hwn math hwnnw? Beth os oedd yn rhyw fath o PHP, lle gall amrywiaeth gynnwys gwahanol fathau mewn gwahanol elfennau?

Ar y pwynt hwn rydych chi'n dechrau meddwl - a oes angen TL o'r fath? Efallai ar gyfer y drol y byddai'n bosibl defnyddio cyfresydd dynol, yr un protobuf a oedd yn bodoli bryd hynny? Dyna oedd y ddamcaniaeth, gadewch i ni edrych ar arfer.

Gweithrediadau TL presennol yn y cod

Ganed TL yn nyfnder VKontakte hyd yn oed cyn y digwyddiadau enwog gyda gwerthiant cyfran Durov a (yn sicr), hyd yn oed cyn i ddatblygiad Telegram ddechrau. Ac mewn ffynhonnell agored cod ffynhonnell y gweithrediad cyntaf gallwch ddod o hyd i lawer o faglau doniol. A gweithredwyd yr iaith ei hun yno yn llawnach nag ydyw yn awr yn Telegram. Er enghraifft, ni ddefnyddir hashes o gwbl yn y cynllun (sy'n golygu ffugdeip adeiledig (fel fector) gydag ymddygiad gwyrdroëdig). Neu

Templates are not used now. Instead, the same universal constructors (for example, vector {t:Type} [t] = Vector t) are used w

ond gadewch i ni ystyried, er mwyn cyflawnder, olrhain, fel petai, esblygiad Cawr y Meddwl.

#define ZHUKOV_BYTES_HACK

#ifdef ZHUKOV_BYTES_HACK

/* dirty hack for Zhukov request */

Neu'r un hardd hon:

    static const char *reserved_words_polymorhic[] = {

      "alpha", "beta", "gamma", "delta", "epsilon", "zeta", "eta", "theta", NULL

      };

Mae'r darn hwn yn ymwneud â thempledi fel:

intHash {alpha:Type} vector<coupleInt<alpha>> = IntHash<alpha>;

Dyma'r diffiniad o dempled hashmap fel fector o int - Math parau. Yn C++ byddai'n edrych rhywbeth fel hyn:

    template <T> class IntHash {
      vector<pair<int,T>> _map;
    }

felly, alpha - allweddair! Ond dim ond yn C ++ y gallwch chi ysgrifennu T, ond dylech chi ysgrifennu alffa, beta ... Ond dim mwy nag 8 paramedrau, dyna lle mae'r ffantasi yn dod i ben. Mae'n ymddangos bod rhai deialogau fel hyn wedi digwydd unwaith yn St.

-- Надо сделать в TL шаблоны
-- Бл... Ну пусть параметры зовут альфа, бета,... Какие там ещё буквы есть... О, тэта!
-- Грамматика? Ну потом напишем

-- Смотрите, какой я синтаксис придумал для шаблонов и вектора!
-- Ты долбанулся, как мы это парсить будем?
-- Да не ссыте, он там один в схеме, захаркодить -- и ок

Ond roedd hyn yn ymwneud â gweithrediad cyhoeddedig cyntaf TL “yn gyffredinol”. Gadewch i ni symud ymlaen i ystyried gweithrediadau yn y cleientiaid Telegram eu hunain.

Gair i Vasily:

Vasily, [09.10.18 17:07] Yn bennaf oll, mae'r asyn yn boeth oherwydd eu bod yn creu criw o dyniadau, ac yna morthwylio bollt arnynt, a gorchuddio'r generadur cod gyda baglau
O ganlyniad, yn gyntaf o doc pilot.jpg
Yna o'r cod dzhekichan.webp

Wrth gwrs, gan bobl sy'n gyfarwydd ag algorithmau a mathemateg, gallwn ddisgwyl eu bod wedi darllen Aho, Ullmann, ac yn gyfarwydd â'r offer sydd wedi dod yn safon de facto yn y diwydiant dros y degawdau ar gyfer ysgrifennu eu casglwyr DSL, dde?..

Awdur telegram-cli yw Vitaly Valtman, fel y gellir ei ddeall o ddigwyddiad y fformat TLO y tu allan i'w ffiniau (cli), aelod o'r tîm - bellach mae llyfrgell ar gyfer dosrannu TL wedi'i neilltuo ar wahân, beth yw'r argraff ohoni Parser TL? ..

16.12 04:18 Vasily: Dwi'n meddwl na wnaeth rhywun feistroli lex+yacc
16.12 04:18 Vasily: Ni allaf ei esbonio fel arall
16.12 04:18 Vasily: wel, neu cawsant eu talu am nifer y llinellau yn VK
16.12 04:19 Vasily: 3k+ llinellau ayyb.<censored> yn lle parser

Eithriad efallai? Gawn ni weld sut yn gwneud Dyma'r cleient SWYDDOGOL - Telegram Desktop:

    nametype = re.match(r'([a-zA-Z.0-9_]+)(#[0-9a-f]+)?([^=]*)=s*([a-zA-Z.<>0-9_]+);', line);
    if (not nametype):
      if (not re.match(r'vector#1cb5c415 {t:Type} # [ t ] = Vector t;', line)):
         print('Bad line found: ' + line);

1100+ o linellau yn Python, cwpl o ymadroddion rheolaidd + achosion arbennig fel fector, sydd, wrth gwrs, yn cael ei ddatgan yn y cynllun fel y dylai fod yn ôl y gystrawen TL, ond roedden nhw'n dibynnu ar y gystrawen hon i'w dosrannu... Mae'r cwestiwn yn codi, pam roedd y cyfan yn wyrth?иMae'n fwy haenog os nad oes unrhyw un yn mynd i'w ddosrannu yn ôl y ddogfennaeth beth bynnag?!

Gyda llaw... Cofiwch inni siarad am wirio CRC32? Felly, yn y generadur cod Telegram Desktop mae rhestr o eithriadau ar gyfer y mathau hynny y cyfrifwyd CRC32 ynddynt ddim yn cyfateb gyda'r un a nodir yn y diagram!

Vasily, [18.12/22 49:XNUMX] ac yma byddwn yn meddwl a oes angen TL o'r fath
pe bawn i eisiau llanast gyda gweithrediadau amgen, byddwn yn dechrau mewnosod toriadau llinell, bydd hanner y parsers yn torri ar ddiffiniadau aml-linell
bwrdd gwaith, fodd bynnag, hefyd

Cofiwch y pwynt am un-leinin, byddwn yn dychwelyd ato ychydig yn ddiweddarach.

Iawn, mae telegram-cli yn answyddogol, mae Telegram Desktop yn swyddogol, ond beth am y lleill? Pwy a wyr?... Yn y cod cleient Android nid oedd parser sgema o gwbl (sy'n codi cwestiynau am ffynhonnell agored, ond mae hyn ar gyfer yr ail ran), ond roedd sawl darn doniol arall o god, ond mwy arnynt yn y is-adran isod.

Pa gwestiynau eraill y mae cyfresoli yn eu codi yn ymarferol? Er enghraifft, gwnaethant lawer o bethau, wrth gwrs, gyda meysydd bit a meysydd amodol:

Vasily: flags.0? true
yn golygu bod y maes yn bresennol ac yn hafal i wir os gosodir y faner

Vasily: flags.1? int
yn golygu bod y cae yn bresennol ac angen ei ddad-gyfresi

Vasily: Ass, peidiwch â phoeni am yr hyn rydych chi'n ei wneud!
Vasily: Mae yna sôn yn rhywle yn y doc mai math moel o hyd sero yw'r gwir, ond mae'n amhosibl cydosod unrhyw beth o'u doc.
Vasily: Yn y gweithrediadau ffynhonnell agored nid yw hyn yn wir ychwaith, ond mae yna griw o faglau a chynhalwyr

Beth am Telethon? Wrth edrych ymlaen at y pwnc o MTProto, enghraifft - yn y ddogfennaeth mae darnau o'r fath, ond yr arwydd % fe’i disgrifir fel “cyfatebol i fath moel penodol” yn unig, h.y. yn yr enghreifftiau isod mae naill ai gwall neu rywbeth heb ei ddogfennu:

Vasily, [22.06.18 18:38] Mewn un lle:

msg_container#73f1f8dc messages:vector message = MessageContainer;

Mewn dull gwahanol:

msg_container#73f1f8dc messages:vector<%Message> = MessageContainer;

Ac mae'r rhain yn ddau wahaniaeth mawr, mewn bywyd go iawn daw rhyw fath o fector noeth

Nid wyf wedi gweld diffiniad fector moel a heb ddod ar draws un

Ysgrifennir y dadansoddiad â llaw mewn telethon

Yn ei ddiagram mae sylwadau ar y diffiniad msg_container

Unwaith eto, erys y cwestiwn tua %. Nid yw'n cael ei ddisgrifio.

Vadim Goncharov, [22.06.18 19:22] ac yn tdesktop?

Vasily, [22.06.18 19:23] Ond mae'n debyg na fydd eu parser TL ar beiriannau rheolaidd yn bwyta hwn chwaith

// parsed manually

Mae TL yn dyniad hardd, nid oes neb yn ei weithredu'n llwyr

Ac nid yw % yn eu fersiwn nhw o'r cynllun

Ond yma mae'r ddogfennaeth yn gwrth-ddweud ei hun, felly idk

Fe'i canfuwyd yn y gramadeg, gallent fod wedi anghofio disgrifio'r semanteg

Fe welsoch chi'r ddogfen ar TL, ni allwch ei chyfrifo heb hanner litr

“Wel, gadewch i ni ddweud,” bydd darllenydd arall yn dweud, “rydych chi'n beirniadu rhywbeth, felly dangoswch i mi sut y dylid ei wneud.”

Atebodd Vasily: “O ran y parser, rwy'n hoffi pethau fel

    args: /* empty */ { $$ = NULL; }
        | args arg { $$ = g_list_append( $1, $2 ); }
        ;

    arg: LC_ID ':' type-term { $$ = tl_arg_new( $1, $3 ); }
            | LC_ID ':' condition '?' type-term { $$ = tl_arg_new_cond( $1, $5, $3 ); free($3); }
            | UC_ID ':' type-term { $$ = tl_arg_new( $1, $3 ); }
            | type-term { $$ = tl_arg_new( "", $1 ); }
            | '[' LC_ID ']' { $$ = tl_arg_new_mult( "", tl_type_new( $2, TYPE_MOD_NONE ) ); }
            ;

rhywsut yn ei hoffi yn well na

struct tree *parse_args4 (void) {
  PARSE_INIT (type_args4);
  struct parse so = save_parse ();
  PARSE_TRY (parse_optional_arg_def);
  if (S) {
    tree_add_child (T, S);
  } else {
    load_parse (so);
  }
  if (LEX_CHAR ('!')) {
    PARSE_ADD (type_exclam);
    EXPECT ("!");
  }
  PARSE_TRY_PES (parse_type_term);
  PARSE_OK;
}

neu

        # Regex to match the whole line
        match = re.match(r'''
            ^                  # We want to match from the beginning to the end
            ([w.]+)           # The .tl object can contain alpha_name or namespace.alpha_name
            (?:
                #             # After the name, comes the ID of the object
                ([0-9a-f]+)    # The constructor ID is in hexadecimal form
            )?                 # If no constructor ID was given, CRC32 the 'tl' to determine it

            (?:s              # After that, we want to match its arguments (name:type)
                {?             # For handling the start of the '{X:Type}' case
                w+            # The argument name will always be an alpha-only name
                :              # Then comes the separator between name:type
                [wd<>#.?!]+  # The type is slightly more complex, since it's alphanumeric and it can
                               # also have Vector<type>, flags:# and flags.0?default, plus :!X as type
                }?             # For handling the end of the '{X:Type}' case
            )*                 # Match 0 or more arguments
            s                 # Leave a space between the arguments and the equal
            =
            s                 # Leave another space between the equal and the result
            ([wd<>#.?]+)     # The result can again be as complex as any argument type
            ;$                 # Finally, the line should always end with ;
            ''', tl, re.IGNORECASE | re.VERBOSE)

dyma'r geiriadur CYFAN:

    ---functions---         return FUNCTIONS;
    ---types---             return TYPES;
    [a-z][a-zA-Z0-9_]*      yylval.string = strdup(yytext); return LC_ID;
    [A-Z][a-zA-Z0-9_]*      yylval.string = strdup(yytext); return UC_ID;
    [0-9]+                  yylval.number = atoi(yytext); return NUM;
    #[0-9a-fA-F]{1,8}       yylval.number = strtol(yytext+1, NULL, 16); return ID_HASH;

    n                      /* skip new line */
    [ t]+                  /* skip spaces */
    //.*$                 /* skip comments */
    /*.**/              /* skip comments */
    .                       return (int)yytext[0];

y rhai. symlach yw ei roi yn ysgafn.”

Yn gyffredinol, o ganlyniad, mae'r parser a'r generadur cod ar gyfer yr is-set o TL a ddefnyddir mewn gwirionedd yn ffitio i oddeutu 100 llinell gramadeg a ~300 llinell o'r generadur (cyfrif y cyfan print' s a gynhyrchir), gan gynnwys byns gwybodaeth teip ar gyfer mewnsylliad ym mhob dosbarth. Mae pob math polymorffig yn troi'n ddosbarth sylfaen haniaethol gwag, ac mae adeiladwyr yn etifeddu ohono ac mae ganddynt ddulliau ar gyfer cyfresoli a dad-gyfeiriannu.

Diffyg mathau yn yr iaith deipio

Mae teipio cryf yn beth da, iawn? Na, nid holivar yw hwn (er bod yn well gennyf ieithoedd deinamig), ond rhagdyb o fewn fframwaith TL. Yn seiliedig arno, dylai'r iaith ddarparu pob math o wiriadau i ni. Wel, iawn, efallai nad ef ei hun, ond y gweithredu, ond dylai o leiaf eu disgrifio. A pha fath o gyfleoedd ydyn ni eisiau?

Yn gyntaf oll, cyfyngiadau. Yma rydym yn gweld yn y ddogfennaeth ar gyfer uwchlwytho ffeiliau:

Yna mae cynnwys deuaidd y ffeil yn cael ei rannu'n rhannau. Rhaid i bob rhan fod yr un maint ( rhan_maint ) a rhaid bodloni’r amodau a ganlyn:

  • part_size % 1024 = 0 (rhannu â 1KB)
  • 524288 % part_size = 0 (Rhaid i 512KB fod yn rhanadwy'n gyfartal yn ôl maint_rhan)

Nid oes rhaid i'r rhan olaf fodloni'r amodau hyn, ar yr amod bod ei maint yn llai na rhan_size.

Dylai fod gan bob rhan rif dilyniant, ffeil_rhan, gyda gwerth yn amrywio o 0 i 2,999.

Ar ôl i'r ffeil gael ei rhannu, mae angen i chi ddewis dull i'w gadw ar y gweinydd. Defnydd upload.saveBigFilePart rhag ofn bod maint llawn y ffeil yn fwy na 10 MB a upload.saveFilePart ar gyfer ffeiliau llai.
[…] gellir dychwelyd un o'r gwallau mewnbynnu data canlynol:

  • FILE_PARTS_INVALID — Nifer annilys o rannau. Nid yw'r gwerth rhwng 1..3000

A oes unrhyw ran o hyn yn y diagram? A yw hyn rywsut yn fynegiannol gan ddefnyddio TL? Nac ydw. Ond esgusodwch fi, roedd hyd yn oed Turbo Pascal taid yn gallu disgrifio'r mathau a nodwyd ystodau. A gwyddai un peth arall, a adwaenir yn well erbyn hyn enum - math sy'n cynnwys rhifiad o nifer sefydlog (bach) o werthoedd. Mewn ieithoedd fel C - rhifol, sylwch mai dim ond am fathau yr ydym wedi siarad hyd yn hyn rhifau. Ond mae yna hefyd araeau, llinynnau ... er enghraifft, byddai'n braf disgrifio mai dim ond rhif ffôn y gall y llinyn hwn ei gynnwys, dde?

Nid oes dim o hyn yn y TL. Ond mae yna, er enghraifft, yn Sgema JSON. Ac os gallai rhywun arall ddadlau ynghylch rhanadwyedd 512 KB, bod angen gwirio hyn yn y cod o hyd, yna gwnewch yn siŵr bod y cleient yn syml. Ni allwn anfon rhif allan o ystod 1..3000 (ac ni allai'r gwall cyfatebol fod wedi codi) byddai wedi bod yn bosibl, iawn?..

Gyda llaw, am wallau a gwerthoedd dychwelyd. Mae hyd yn oed y rhai sydd wedi gweithio gyda TL yn pylu eu llygaid - ni wawriodd hynny arnom ar unwaith pob un gall swyddogaeth yn TL ddychwelyd nid yn unig y math dychwelyd a ddisgrifir, ond gwall hefyd. Ond ni ellir diddwytho hyn mewn unrhyw ffordd gan ddefnyddio'r TL ei hun. Wrth gwrs, mae eisoes yn glir ac nid oes angen unrhyw beth yn ymarferol (er mewn gwirionedd, gellir gwneud RPC mewn gwahanol ffyrdd, fe ddown yn ôl at hyn yn nes ymlaen) - ond beth am Burdeb cysyniadau Mathemateg o Mathau Haniaethol o'r byd nefol?.. Fe wnes i godi'r tynnu - felly parwch.

Ac yn olaf, beth am ddarllenadwyedd? Wel, yno, yn gyffredinol, hoffwn disgrifiad ei wneud yn iawn yn y sgema (yn sgema JSON, eto, y mae), ond os ydych eisoes dan straen ag ef, yna beth am yr ochr ymarferol - o leiaf yn edrych yn ddibwys ar diffs yn ystod diweddariadau? Gweler drosoch eich hun yn enghreifftiau go iawn:

-channelFull#76af5481 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int = ChatFull;
+channelFull#1c87a71a flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_view_stats:flags.12?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int = ChatFull;

neu

-message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message;
+message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message;

Mae'n dibynnu ar bawb, ond mae GitHub, er enghraifft, yn gwrthod tynnu sylw at newidiadau y tu mewn i linellau mor hir. Y gêm "dod o hyd i 10 gwahaniaeth", a'r hyn y mae'r ymennydd yn ei weld ar unwaith yw bod y dechreuadau a'r diwedd yn y ddwy enghraifft yr un peth, mae angen i chi ddarllen yn ddiflas rhywle yn y canol ... Yn fy marn i, nid mewn theori yn unig y mae hyn, ond yn weledol yn unig fudr a blêr.

Gyda llaw, am burdeb y ddamcaniaeth. Pam mae angen bit fields? Onid yw'n ymddangos eu bod arogli drwg o safbwynt theori teip? Mae'r esboniad i'w weld mewn fersiynau cynharach o'r diagram. Ar y dechrau, ie, dyna fel y bu, ar gyfer pob tisian crëwyd math newydd. Mae'r elfennau hyn yn dal i fodoli yn y ffurf hon, er enghraifft:

storage.fileUnknown#aa963b05 = storage.FileType;
storage.filePartial#40bc6f52 = storage.FileType;
storage.fileJpeg#7efe0e = storage.FileType;
storage.fileGif#cae1aadf = storage.FileType;
storage.filePng#a4f63c0 = storage.FileType;
storage.filePdf#ae1e508d = storage.FileType;
storage.fileMp3#528a0677 = storage.FileType;
storage.fileMov#4b09ebbc = storage.FileType;
storage.fileMp4#b3cea0e4 = storage.FileType;
storage.fileWebp#1081464c = storage.FileType;

Ond nawr dychmygwch, os oes gennych 5 maes dewisol yn eich strwythur, yna bydd angen 32 math arnoch ar gyfer pob opsiwn posibl. Ffrwydrad cyfun. Felly, chwalodd purdeb grisial y ddamcaniaeth TL unwaith eto yn erbyn asyn haearn bwrw realiti llym cyfresoli.

Yn ogystal, mewn rhai mannau mae'r dynion hyn eu hunain yn torri eu teipoleg eu hunain. Er enghraifft, yn MTProto (pennod nesaf) gall yr ymateb gael ei gywasgu gan Gzip, mae popeth yn iawn - ac eithrio bod yr haenau a'r cylched yn cael eu torri. Unwaith eto, nid RpcResult ei hun a gafodd ei fedi, ond ei gynnwys. Wel, pam gwneud hyn?... Roedd yn rhaid i mi dorri i mewn i faglau fel y byddai'r cywasgu yn gweithio yn unrhyw le.

Neu enghraifft arall, fe wnaethom ddarganfod gwall unwaith - fe'i hanfonwyd InputPeerUser yn hytrach na InputUser. Neu i'r gwrthwyneb. Ond fe weithiodd! Hynny yw, nid oedd y gweinydd yn poeni am y math. Sut gall hyn fod? Gellir rhoi'r ateb i ni trwy ddarnau cod o telegram-cli:

  if (tgl_get_peer_type (E->id) != TGL_PEER_CHANNEL || (C && (C->flags & TGLCHF_MEGAGROUP))) {
    out_int (CODE_messages_get_history);
    out_peer_id (TLS, E->id);
  } else {    
    out_int (CODE_channels_get_important_history);

    out_int (CODE_input_channel);
    out_int (tgl_get_peer_id (E->id));
    out_long (E->id.access_hash);
  }
  out_int (E->max_id);
  out_int (E->offset);
  out_int (E->limit);
  out_int (0);
  out_int (0);

Mewn geiriau eraill, dyma lle mae cyfresoli yn cael ei wneud LLAW, cod heb ei gynhyrchu! Efallai bod y gweinydd yn cael ei weithredu mewn ffordd debyg?... Mewn egwyddor, bydd hyn yn gweithio os caiff ei wneud unwaith, ond sut y gellir ei gefnogi yn ddiweddarach yn ystod diweddariadau? Ai dyma pam y dyfeisiwyd y cynllun? A dyma symud ymlaen at y cwestiwn nesaf.

Fersiynu. Haenau

Dim ond ar sail hanes sgematigau cyhoeddedig y gellir dyfalu pam y gelwir y fersiynau sgematig yn haenau. Mae'n debyg, ar y dechrau roedd yr awduron o'r farn y gellid gwneud pethau sylfaenol gan ddefnyddio'r cynllun heb ei newid, a dim ond lle bo angen, ar gyfer ceisiadau penodol, nodi eu bod yn cael eu gwneud gan ddefnyddio fersiwn wahanol. Mewn egwyddor, hyd yn oed syniad da - a bydd y newydd, fel petai, yn “gymysg”, haenog ar ben yr hen. Ond gadewch i ni weld sut y cafodd ei wneud. Yn wir, nid oeddwn yn gallu edrych arno o'r cychwyn cyntaf - mae'n ddoniol, ond nid yw'r diagram o'r haen sylfaen yn bodoli. Dechreuodd haenau gyda 2. Mae'r ddogfennaeth yn dweud wrthym am nodwedd TL arbennig:

Os yw cleient yn cefnogi Haen 2, yna rhaid defnyddio'r lluniwr canlynol:

invokeWithLayer2#289dd1f6 {X:Type} query:!X = X;

Yn ymarferol, mae hyn yn golygu bod cyn pob galwad API, int gyda'r gwerth 0x289dd1f6 rhaid ei ychwanegu cyn rhif y dull.

Swnio'n normal. Ond beth ddigwyddodd nesaf? Yna ymddangosodd

invokeWithLayer3#b7475268 query:!X = X;

Felly beth sydd nesaf? Fel y gallech ddyfalu,

invokeWithLayer4#dea0d430 query:!X = X;

Doniol? Na, mae'n rhy gynnar i chwerthin, meddyliwch am y ffaith bod bob mae angen lapio cais o haen arall mewn math mor arbennig - os ydyn nhw i gyd yn wahanol i chi, sut arall allwch chi eu gwahaniaethu? Ac mae ychwanegu dim ond 4 beit o'ch blaen yn ddull eithaf effeithlon. Felly,

invokeWithLayer5#417a57ae query:!X = X;

Ond mae'n amlwg ar ôl ychydig y bydd hyn yn dod yn rhyw fath o bacchanalia. A daeth yr ateb:

Diweddariad: Gan ddechrau gyda Haen 9, dulliau helpwr invokeWithLayerN gellir ei ddefnyddio yn unig ynghyd â initConnection

Hwre! Ar ôl 9 fersiwn, daethom o'r diwedd at yr hyn a wnaed mewn protocolau Rhyngrwyd yn ôl yn yr 80au - cytuno ar y fersiwn unwaith ar ddechrau'r cysylltiad!

Felly beth sydd nesaf?..

invokeWithLayer10#39620c41 query:!X = X;
...
invokeWithLayer18#1c900537 query:!X = X;

Ond nawr gallwch chi chwerthin o hyd. Dim ond ar ôl 9 haen arall, ychwanegwyd lluniwr cyffredinol gyda rhif fersiwn o'r diwedd, y mae angen ei alw unwaith yn unig ar ddechrau'r cysylltiad, ac roedd yn ymddangos bod ystyr yr haenau wedi diflannu, nawr dim ond fersiwn amodol ydyw, fel ym mhob man arall. Problem wedi'i datrys.

Yn union?..

Vasily, [16.07.18 14:01] Hyd yn oed ddydd Gwener meddyliais:
Mae'r teleserver yn anfon digwyddiadau heb gais. Rhaid i geisiadau gael eu lapio yn InvokeWithLayer. Nid yw'r gweinydd yn lapio diweddariadau; nid oes strwythur ar gyfer lapio ymatebion a diweddariadau.

Y rhai. ni all y cleient nodi'r haen y mae eisiau diweddariadau ynddi

Vadim Goncharov, [16.07.18 14:02] onid yw InvokeWithLayer yn faglau mewn egwyddor?

Vasily, [16.07.18 14:02] Dyma'r unig ffordd

Vadim Goncharov, [16.07.18 14:02] a ddylai yn ei hanfod olygu cytuno ar yr haen ar ddechrau'r sesiwn

Gyda llaw, mae'n dilyn na ddarperir israddio cleient

Diweddariadau, h.y. math Updates yn y cynllun, dyma beth mae'r gweinydd yn ei anfon at y cleient nid mewn ymateb i gais API, ond yn annibynnol pan fydd digwyddiad yn digwydd. Mae hwn yn bwnc cymhleth a fydd yn cael ei drafod mewn swydd arall, ond am y tro mae'n bwysig gwybod bod y gweinydd yn arbed Diweddariadau hyd yn oed pan fydd y cleient all-lein.

Felly, os byddwch yn gwrthod lapio yr un pecyn i nodi ei fersiwn, mae hyn yn rhesymegol yn arwain at y problemau posibl canlynol:

  • mae'r gweinydd yn anfon diweddariadau i'r cleient hyd yn oed cyn i'r cleient hysbysu pa fersiwn y mae'n ei gefnogi
  • Beth ddylwn i ei wneud ar ôl uwchraddio'r cleient?
  • sy'n gwarantauna fydd barn y gweinydd am y rhif haen yn newid yn ystod y broses?

Ydych chi'n meddwl mai dyfalu damcaniaethol yn unig yw hwn, ac yn ymarferol ni all hyn ddigwydd, oherwydd bod y gweinydd wedi'i ysgrifennu'n gywir (o leiaf, mae'n cael ei brofi'n dda)? Ha! Dim ots sut y mae!

Dyma'n union beth wnaethon ni redeg i mewn iddo ym mis Awst. Ar Awst 14, roedd negeseuon bod rhywbeth yn cael ei ddiweddaru ar weinyddion Telegram ... ac yna yn y logiau:

2019-08-15 09:28:35.880640 MSK warn  main: ANON:87: unknown object type: 0x80d182d1 at TL/Object.pm line 213.
2019-08-15 09:28:35.751899 MSK warn  main: ANON:87: unknown object type: 0xb5223b0f at TL/Object.pm line 213.

ac yna sawl megabeit o olion pentwr (wel, ar yr un pryd roedd y logio yn sefydlog). Wedi'r cyfan, os nad yw rhywbeth yn cael ei gydnabod yn eich TL, mae'n ddeuaidd trwy lofnod, ymhellach i lawr y llinell I GYD yn mynd, bydd dadgodio yn dod yn amhosibl. Beth ddylech chi ei wneud mewn sefyllfa o'r fath?

Wel, y peth cyntaf sy'n dod i feddwl unrhyw un yw datgysylltu a cheisio eto. Heb helpu. Rydyn ni'n google CRC32 - trodd y rhain yn wrthrychau o gynllun 73, er i ni weithio ar 82. Edrychwn yn ofalus ar y logiau - mae dynodwyr o ddau gynllun gwahanol!

Efallai bod y broblem yn ein cleient answyddogol yn unig? Na, rydym yn lansio Telegram Desktop 1.2.17 (fersiwn a gyflenwir mewn nifer o ddosbarthiadau Linux), mae'n ysgrifennu at y log Eithriad: MTP Math annisgwyl id #b5223b0f wedi'i ddarllen yn MTPMessageMedia…

Beirniadaeth o brotocol a dulliau sefydliadol Telegram. Rhan 1, technegol: profiad o ysgrifennu cleient o'r dechrau - TL, MT

Dangosodd Google fod problem debyg eisoes wedi digwydd i un o'r cleientiaid answyddogol, ond yna roedd niferoedd y fersiwn ac, yn unol â hynny, y rhagdybiaethau yn wahanol ...

Felly beth ddylem ni ei wneud? Gwahanodd Vasily a minnau: ceisiodd ddiweddaru'r gylched i 91, penderfynais aros ychydig ddyddiau a cheisio ar 73. Gweithiodd y ddau ddull, ond gan eu bod yn empirig, nid oes unrhyw ddealltwriaeth o faint o fersiynau i fyny neu i lawr sydd eu hangen arnoch i neidio, neu pa mor hir y mae angen i chi aros .

Yn ddiweddarach llwyddais i atgynhyrchu'r sefyllfa: rydym yn lansio'r cleient, yn ei ddiffodd, yn ail-grynhoi'r gylched i haen arall, yn ailgychwyn, yn dal y broblem eto, yn dychwelyd i'r un blaenorol - wps, dim swm o newid cylched ac mae'r cleient yn ailgychwyn am a bydd ychydig funudau o gymorth. Byddwch yn derbyn cymysgedd o strwythurau data o wahanol haenau.

Eglurhad? Fel y gallwch chi ddyfalu o wahanol symptomau anuniongyrchol, mae'r gweinydd yn cynnwys llawer o brosesau o wahanol fathau ar wahanol beiriannau. Yn fwyaf tebygol, mae'r gweinydd sy'n gyfrifol am “byffro” wedi rhoi yn y ciw yr hyn a roddodd ei uwch swyddogion iddo, ac fe wnaethant ei roi yn y cynllun a oedd ar waith ar adeg cynhyrchu. A hyd nes y ciw hwn yn “pydru”, ni ellid gwneud dim amdano.

Efallai... ond mae hwn yn fagwrfa ofnadwy?!... Na, cyn meddwl am syniadau gwallgof, gadewch i ni edrych ar god y cleientiaid swyddogol. Yn y fersiwn Android nid ydym yn dod o hyd i unrhyw parser TL, ond rydym yn dod o hyd i ffeil hefty (GitHub yn gwrthod cyffwrdd i fyny) gyda (dad) serialization. Dyma'r pytiau cod:

public static class TL_message_layer68 extends TL_message {
    public static int constructor = 0xc09be45f;
//...
//еще пачка подобных
//...
    public static class TL_message_layer47 extends TL_message {
        public static int constructor = 0xc992e15c;
        public static Message TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) {
            Message result = null;
            switch (constructor) {
                case 0x1d86f70e:
                    result = new TL_messageService_old2();
                    break;
                case 0xa7ab1991:
                    result = new TL_message_old3();
                    break;
                case 0xc3060325:
                    result = new TL_message_old4();
                    break;
                case 0x555555fa:
                    result = new TL_message_secret();
                    break;
                case 0x555555f9:
                    result = new TL_message_secret_layer72();
                    break;
                case 0x90dddc11:
                    result = new TL_message_layer72();
                    break;
                case 0xc09be45f:
                    result = new TL_message_layer68();
                    break;
                case 0xc992e15c:
                    result = new TL_message_layer47();
                    break;
                case 0x5ba66c13:
                    result = new TL_message_old7();
                    break;
                case 0xc06b9607:
                    result = new TL_messageService_layer48();
                    break;
                case 0x83e5de54:
                    result = new TL_messageEmpty();
                    break;
                case 0x2bebfa86:
                    result = new TL_message_old6();
                    break;
                case 0x44f9b43d:
                    result = new TL_message_layer104();
                    break;
                case 0x1c9b1027:
                    result = new TL_message_layer104_2();
                    break;
                case 0xa367e716:
                    result = new TL_messageForwarded_old2(); //custom
                    break;
                case 0x5f46804:
                    result = new TL_messageForwarded_old(); //custom
                    break;
                case 0x567699b3:
                    result = new TL_message_old2(); //custom
                    break;
                case 0x9f8d60bb:
                    result = new TL_messageService_old(); //custom
                    break;
                case 0x22eb6aba:
                    result = new TL_message_old(); //custom
                    break;
                case 0x555555F8:
                    result = new TL_message_secret_old(); //custom
                    break;
                case 0x9789dac4:
                    result = new TL_message_layer104_3();
                    break;

neu

    boolean fixCaption = !TextUtils.isEmpty(message) &&
    (media instanceof TLRPC.TL_messageMediaPhoto_old ||
     media instanceof TLRPC.TL_messageMediaPhoto_layer68 ||
     media instanceof TLRPC.TL_messageMediaPhoto_layer74 ||
     media instanceof TLRPC.TL_messageMediaDocument_old ||
     media instanceof TLRPC.TL_messageMediaDocument_layer68 ||
     media instanceof TLRPC.TL_messageMediaDocument_layer74)
    && message.startsWith("-1");

Hmm... edrych yn wyllt. Ond, yn ôl pob tebyg, mae hyn yn cael ei gynhyrchu cod, yna iawn?.. Ond mae'n sicr yn cefnogi pob fersiwn! Yn wir, nid yw'n glir pam mae popeth yn gymysg â'i gilydd, sgyrsiau cyfrinachol, a phob math o _old7 rhywsut ddim yn edrych fel cynhyrchu peiriannau... Fodd bynnag, yn bennaf oll cefais fy synnu gan

TL_message_layer104
TL_message_layer104_2
TL_message_layer104_3

Guys, allwch chi ddim hyd yn oed benderfynu beth sydd y tu mewn i un haen?! Wel, iawn, gadewch i ni ddweud "dau" wedi'u rhyddhau gyda gwall, wel, mae'n digwydd, ond TRI?.. Ar unwaith, yr un rhaca eto? Pa fath o bornograffi yw hwn, sori?..

Yn y cod ffynhonnell Telegram Desktop, gyda llaw, mae peth tebyg yn digwydd - os felly, nid yw sawl un yn ymrwymo yn olynol i'r cynllun yn newid ei rif haen, ond yn trwsio rhywbeth. Mewn amodau lle nad oes ffynhonnell ddata swyddogol ar gyfer y cynllun, o ble y gellir ei gael, ac eithrio cod ffynhonnell y cleient swyddogol? Ac os cymerwch ef oddi yno, ni allwch fod yn sicr bod y cynllun yn gwbl gywir nes i chi brofi'r holl ddulliau.

Sut y gellir profi hyn hyd yn oed? Rwy'n gobeithio y bydd cefnogwyr profion uned, swyddogaethol a phrofion eraill yn rhannu'r sylwadau.

Iawn, gadewch i ni edrych ar ddarn arall o god:

public static class TL_folders_deleteFolder extends TLObject {
    public static int constructor = 0x1c295881;

    public int folder_id;

    public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) {
        return Updates.TLdeserialize(stream, constructor, exception);
    }

    public void serializeToStream(AbstractSerializedData stream) {
        stream.writeInt32(constructor);
        stream.writeInt32(folder_id);
    }
}

//manually created

//RichText start
public static abstract class RichText extends TLObject {
    public String url;
    public long webpage_id;
    public String email;
    public ArrayList<RichText> texts = new ArrayList<>();
    public RichText parentRichText;

    public static RichText TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) {
        RichText result = null;
        switch (constructor) {
            case 0x1ccb966a:
                result = new TL_textPhone();
                break;
            case 0xc7fb5e01:
                result = new TL_textSuperscript();
                break;

Mae'r sylw hwn “wedi'i greu â llaw” yn awgrymu mai dim ond rhan o'r ffeil hon a ysgrifennwyd â llaw (allwch chi ddychmygu'r hunllef cynnal a chadw gyfan?), a chynhyrchwyd y gweddill â pheiriant. Fodd bynnag, yna mae cwestiwn arall yn codi - bod y ffynonellau ar gael ddim yn llwyr (a la smotiau GPL yn y cnewyllyn Linux), ond mae hwn eisoes yn bwnc ar gyfer yr ail ran.

Ond digon. Gadewch i ni symud ymlaen at y protocol y mae'r holl gyfresoli hwn yn rhedeg ar ei ben.

Proto MT

Felly, gadewch i ni agor disgrifiad cyffredinol и disgrifiad manwl o'r protocol a'r peth cyntaf yr ydym yn baglu drosto yw'r derminoleg. A chyda digonedd o bopeth. Yn gyffredinol, mae'n ymddangos bod hyn yn nodwedd berchnogol Telegram - galw pethau'n wahanol mewn gwahanol leoedd, neu bethau gwahanol gydag un gair, neu i'r gwrthwyneb (er enghraifft, mewn API lefel uchel, os gwelwch becyn sticer, nid yw'n beth oeddech chi'n ei feddwl).

Er enghraifft, mae “neges” a “sesiwn” yn golygu rhywbeth gwahanol yma nag yn y rhyngwyneb cleient Telegram arferol. Wel, mae popeth yn glir gyda'r neges, gellid ei ddehongli mewn termau OOP, neu ei alw'n syml y gair “pecyn” - mae hwn yn lefel trafnidiaeth isel, nid oes yr un negeseuon ag yn y rhyngwyneb, mae yna lawer o negeseuon gwasanaeth . Ond y sesiwn... ond pethau cyntaf yn gyntaf.

haen trafnidiaeth

Y peth cyntaf yw trafnidiaeth. Byddant yn dweud wrthym am 5 opsiwn:

  • TCP
  • Soced gwe
  • Websocket dros HTTPS
  • HTTP
  • HTTPS

Vasily, [15.06.18 15:04] Mae cludiant CDU hefyd, ond nid yw wedi'i ddogfennu

A TCP mewn tri amrywiad

Mae'r un cyntaf yn debyg i CDU dros TCP, mae pob pecyn yn cynnwys rhif dilyniant a chrc
Pam mae darllen dogfennau ar drol mor boenus?

Wel, dyna hi nawr TCP eisoes mewn 4 amrywiad:

  • Wedi'i bontio
  • Canolradd
  • Canolradd padio
  • Llawn

Wel, iawn, canolradd Padded ar gyfer MTProxy, ychwanegwyd hyn yn ddiweddarach oherwydd digwyddiadau adnabyddus. Ond pam dwy fersiwn arall (tri i gyd) pan allech chi ddod ymlaen ag un? Yn y bôn, mae'r pedwar yn wahanol yn unig o ran sut i osod hyd a llwyth tâl y prif MTProto, a drafodir ymhellach:

  • yn Talfyredig yw 1 neu 4 bytes, ond nid 0xef, yna y corff
  • yn y Canolradd mae hyn yn 4 bytes o hyd a maes, a'r tro cyntaf y mae'n rhaid i'r cleient anfon 0xeeeeeeee i ddangos ei fod yn Ganolradd
  • yn Llawn y mwyaf caethiwus, o safbwynt rhwydwaithwr: hyd, rhif dilyniant, ac NID YR UN sy'n bennaf yn MTProto, corff, CRC32. Ydy, mae hyn i gyd ar ben TCP. Sy'n darparu cludiant dibynadwy i ni ar ffurf ffrwd beit ddilyniannol; nid oes angen dilyniannau, yn enwedig sieciau. Iawn, nawr bydd rhywun yn gwrthwynebu i mi fod gan TCP siec 16-did, felly mae llygredd data yn digwydd. Gwych, ond mewn gwirionedd mae gennym ni brotocol cryptograffig gyda hashes yn hirach na 16 bytes, bydd yr holl wallau hyn - a hyd yn oed mwy - yn cael eu dal gan ddiffyg cyfatebiaeth SHA ar lefel uwch. Nid oes unrhyw bwynt yn CRC32 ar ben hyn.

Gadewch i ni gymharu Talfyredig, lle mae un beit o hyd yn bosibl, gyda Chanolradd, sy'n cyfiawnhau “Rhag ofn bod angen aliniad data 4-beit,” sy'n eithaf nonsens. Beth, y credir bod rhaglenwyr Telegram mor anghymwys fel na allant ddarllen data o soced i mewn i glustog wedi'i alinio? Mae'n rhaid i chi wneud hyn o hyd, oherwydd gall darllen ddychwelyd unrhyw nifer o beitau i chi (ac mae yna weinyddion dirprwy hefyd, er enghraifft...). Neu ar y llaw arall, pam bloc Talfyrwyd os byddwn yn dal i gael padin hefty ar ben 16 beit - arbed 3 beit weithiau ?

Mae un yn cael yr argraff bod Nikolai Durov wir yn hoffi ailddyfeisio olwynion, gan gynnwys protocolau rhwydwaith, heb unrhyw angen ymarferol gwirioneddol.

Opsiynau trafnidiaeth eraill, gan gynnwys. Web a MTProxy, ni fyddwn yn ystyried nawr, efallai mewn swydd arall, os oes cais. Ynglŷn â'r un MTProxy hwn, gadewch inni gofio nawr, yn fuan ar ôl ei ryddhau yn 2018, bod darparwyr wedi dysgu'n gyflym i'w rwystro, y bwriadwyd ei wneud ar gyfer blocio ffordd osgoigan maint pecyn! A hefyd y ffaith bod y gweinydd MTProxy a ysgrifennwyd (eto gan Waltman) yn C yn rhy gysylltiedig â manylion Linux, er nad oedd angen hyn o gwbl (bydd Phil Kulin yn cadarnhau), ac y byddai gweinydd tebyg naill ai yn Go neu Node.js ffitio mewn llai na chant o linellau.

Ond byddwn yn dod i gasgliadau am lythrennedd technegol y bobl hyn ar ddiwedd yr adran, ar ôl ystyried materion eraill. Am y tro, gadewch i ni symud ymlaen i OSI haen 5, sesiwn - y maent yn gosod MTProto sesiwn.

Allweddi, negeseuon, sesiynau, Diffie-Hellman

Fe wnaethon nhw ei osod yno ddim yn hollol gywir... Nid yw sesiwn yr un sesiwn sydd i'w gweld yn y rhyngwyneb o dan sesiynau Actif. Ond mewn trefn.

Beirniadaeth o brotocol a dulliau sefydliadol Telegram. Rhan 1, technegol: profiad o ysgrifennu cleient o'r dechrau - TL, MT

Felly cawsom llinyn beit o hyd hysbys o'r haen gludo. Mae hon naill ai'n neges wedi'i hamgryptio neu'n destun plaen - os ydym yn dal ar y cam cytundeb allweddol ac yn ei wneud mewn gwirionedd. Am ba un o'r criw o gysyniadau a elwir yn “allweddol” rydyn ni'n siarad? Gadewch i ni egluro'r mater hwn i dîm Telegram ei hun (ymddiheuraf am gyfieithu fy nogfennaeth fy hun o'r Saesneg gydag ymennydd blinedig am 4 am, roedd yn haws gadael rhai ymadroddion fel y maent):

Mae dau endid o'r enw Sesiwn - un yn UI cleientiaid swyddogol o dan “sesiynau cyfredol”, lle mae pob sesiwn yn cyfateb i ddyfais / OS cyfan.
Ail - Sesiwn MTProto, sydd â rhif dilyniant y neges (mewn ystyr lefel isel) ynddo, a pha gall bara rhwng gwahanol gysylltiadau TCP. Gellir gosod sawl sesiwn MTProto ar yr un pryd, er enghraifft, i gyflymu lawrlwytho ffeiliau.

Rhwng y ddau hyn sesiynau mae cysyniad awdurdodiad. Yn yr achos dirywiol, gallwn ddweud hynny Sesiwn UI yr un fath a awdurdodiad, ond gwaetha'r modd, mae popeth yn gymhleth. Gadewch i ni edrych:

  • Mae'r defnyddiwr ar y ddyfais newydd yn cynhyrchu gyntaf awdurdod_allwedd ac yn ei rwymo i gyfrif, er enghraifft trwy SMS - dyna pam awdurdodiad
  • Digwyddodd y tu mewn i'r cyntaf Sesiwn MTProto, sydd wedi session_id y tu mewn i chi'ch hun.
  • Ar y cam hwn, y cyfuniad awdurdodiad и session_id gellid ei alw enghraifft - mae'r gair hwn yn ymddangos yn nogfennaeth a chod rhai cleientiaid
  • Yna, gall y cleient agor rhai Sesiynau MTProto dan yr un awdurdod_allwedd - i'r un DC.
  • Yna, un diwrnod bydd angen i'r cleient ofyn am y ffeil DC arall - ac ar gyfer y DC hwn bydd un newydd yn cael ei gynhyrchu awdurdod_allwedd !
  • Hysbysu'r system nad defnyddiwr newydd sy'n cofrestru, ond yr un peth awdurdodiad (Sesiwn UI), mae'r cleient yn defnyddio galwadau API auth.exportAuthorization yn y cartref DC auth.importAuthorization yn y DC newydd.
  • Mae popeth yr un peth, efallai y bydd sawl un yn agored Sesiynau MTProto (pob un â'i hun session_id) i'r DC newydd hwn, dan ei awdurdod_allwedd.
  • Yn olaf, efallai y bydd y cleient eisiau Cyfrinachedd Ymlaen Perffaith. Pob awdurdod_allwedd oedd parhaol allweddol - fesul DC - a gall y cleient ffonio auth.bindTempAuthKey ar gyfer defnydd dros dro awdurdod_allwedd - ac eto, dim ond un allwedd temp_auth_ fesul DC, sy'n gyffredin i bawb Sesiynau MTProto i'r DC hwn.

Sylwch ar hynny halen (a halwynau'r dyfodol) hefyd yn un ymlaen awdurdod_allwedd y rhai. rhannu rhwng pawb Sesiynau MTProto i'r un DC.

Beth mae "rhwng gwahanol gysylltiadau TCP" yn ei olygu? Felly mae hyn yn golygu rhywbeth tebyg cwci awdurdodi ar wefan - mae'n parhau (yn goroesi) llawer o gysylltiadau TCP â gweinydd penodol, ond un diwrnod mae'n mynd yn ddrwg. Dim ond yn wahanol i HTTP, mewn MTProto mae negeseuon o fewn sesiwn yn cael eu rhifo a'u cadarnhau'n ddilyniannol; os aethant i mewn i'r twnnel, torrwyd y cysylltiad - ar ôl sefydlu cysylltiad newydd, bydd y gweinydd yn garedig yn anfon popeth yn y sesiwn hon na chyflwynodd yn y blaenorol Cysylltiad TCP.

Fodd bynnag, mae'r wybodaeth uchod yn cael ei chrynhoi ar ôl misoedd lawer o ymchwilio. Yn y cyfamser, a ydym yn gweithredu ein cleient o'r dechrau? - gadewch i ni fynd yn ôl i'r dechrau.

Felly gadewch i ni gynhyrchu auth_key ar Fersiynau Diffie-Hellman o Telegram. Gadewch i ni geisio deall y ddogfennaeth...

Vasily, [19.06.18 20:05] data_with_hash := SHA1(data) + data + (unrhyw beit ar hap); fel bod yr hyd yn hafal i 255 beit;
encrypted_data := RSA(data_with_hash, server_public_key); mae rhif 255-beit o hyd (endian mawr) yn cael ei godi i'r pŵer angenrheidiol dros y modwlws gofynnol, ac mae'r canlyniad yn cael ei storio fel rhif 256-beit.

Mae ganddyn nhw rywfaint o dope DH

Nid yw'n edrych fel DH person iach
Nid oes dwy allwedd gyhoeddus yn dx

Wel, yn y diwedd cafodd hyn ei ddatrys, ond arhosodd gweddill - prawf o waith yn cael ei wneud gan y cleient ei fod yn gallu ffactorio'r rhif. Math o amddiffyniad rhag ymosodiadau DoS. A dim ond unwaith mewn un cyfeiriad y defnyddir yr allwedd RSA, yn y bôn ar gyfer amgryptio new_nonce. Ond er y bydd y llawdriniaeth hon sy'n ymddangos yn syml yn llwyddo, beth fydd yn rhaid i chi ei wynebu?

Vasily, [20.06.18/00/26 XNUMX:XNUMX] Nid wyf wedi cyrraedd y cais apid eto

Anfonais y cais hwn at DH

Ac, yn y doc trafnidiaeth mae'n dweud y gall ymateb gyda 4 bytes o god gwall. Dyna i gyd

Wel, dywedodd wrthyf -404, felly beth?

Felly dywedais wrtho: “Daliwch eich bullshit wedi'i amgryptio ag allwedd gweinydd gydag olion bysedd fel hyn, rydw i eisiau DH,” ac ymatebodd gyda 404 dwp

Beth fyddech chi'n ei feddwl o'r ymateb gweinydd hwn? Beth i'w wneud? Nid oes neb i ofyn (ond mwy ar hynny yn yr ail ran).

Yma mae'r holl log yn cael ei wneud ar y doc

Does gen i ddim byd arall i'w wneud, nes i freuddwydio am drosi rhifau yn ôl ac ymlaen

Dau rif 32 did. Fe wnes i eu pacio fel pawb arall

Ond na, mae angen ychwanegu'r ddau hyn at y llinell yn gyntaf fel BE

Vadim Goncharov, [20.06.18 15:49] ac oherwydd hyn 404?

Vasily, [20.06.18 15:49] OES!

Vadim Goncharov, [20.06.18 15:50] felly dydw i ddim yn deall yr hyn y gall “ddim wedi dod o hyd iddo”

Vasily, [20.06.18 15:50] oddeutu

Ni allwn ddod o hyd i ddadelfennu o'r fath yn ffactorau cysefin%)

Ni wnaethom hyd yn oed reoli adrodd ar wallau

Vasily, [20.06.18 20:18] O, mae yna MD5 hefyd. Tri hashes gwahanol yn barod

Mae'r olion bysedd allweddol yn cael ei gyfrifo fel a ganlyn:

digest = md5(key + iv)
fingerprint = substr(digest, 0, 4) XOR substr(digest, 4, 4)

SHA1 a sha2

Felly gadewch i ni ei roi auth_key cawsom 2048 o ddarnau o faint gan ddefnyddio Diffie-Hellman. Beth sydd nesaf? Nesaf rydym yn darganfod nad yw'r darnau 1024 isaf o'r allwedd hon yn cael eu defnyddio mewn unrhyw ffordd ... ond gadewch i ni feddwl am hyn am y tro. Ar y cam hwn, mae gennym gyfrinach a rennir gyda'r gweinydd. Mae analog o'r sesiwn TLS wedi'i sefydlu, sy'n weithdrefn ddrud iawn. Ond nid yw'r gweinydd yn gwybod dim am bwy ydym ni o hyd! Ddim eto, mewn gwirionedd. awdurdodiad. Y rhai. os oeddech yn meddwl yn nhermau “mewngofnodi-cyfrinair”, fel y gwnaethoch unwaith yn ICQ, neu o leiaf “login-key”, fel yn SSH (er enghraifft, ar rai gitlab/gitub). Cawsom un dienw. Beth os bydd y gweinydd yn dweud wrthym “mae'r rhifau ffôn hyn yn cael eu gwasanaethu gan DC arall”? Neu hyd yn oed “mae eich rhif ffôn wedi ei wahardd”? Y gorau y gallwn ei wneud yw cadw'r allwedd yn y gobaith y bydd yn ddefnyddiol ac na fydd yn pydru erbyn hynny.

Gyda llaw, fe wnaethon ni ei “derbyn” gydag amheuon. Er enghraifft, ydyn ni'n ymddiried yn y gweinydd? Beth os yw'n ffug? Byddai angen gwiriadau cryptograffig:

Vasily, [21.06.18 17:53] Maen nhw'n cynnig cleientiaid symudol i wirio rhif 2kbit ar gyfer uchafiaeth%)

Ond nid yw'n glir o gwbl, nafeijoa

Vasily, [21.06.18 18:02] Nid yw'r ddogfen yn dweud beth i'w wneud os nad yw'n syml

Heb ei ddweud. Gadewch i ni weld beth mae'r cleient Android swyddogol yn ei wneud yn yr achos hwn? A dyna beth (ac ydy, mae'r ffeil gyfan yn ddiddorol) - fel maen nhw'n dweud, wna i jest gadael hwn fan hyn:

278     static const char *goodPrime = "c71caeb9c6b1c9048e6c522f70f13f73980d40238e3e21c14934d037563d930f48198a0aa7c14058229493d22530f4dbfa336f6e0ac925139543aed44cce7c3720fd51f69458705ac68cd4fe6b6b13abdc9746512969328454f18faf8c595f642477fe96bb2a941d5bcd1d4ac8cc49880708fa9b378e3c4f3a9060bee67cf9a4a4a695811051907e162753b56b0f6b410dba74d8a84b2a14b3144e0ef1284754fd17ed950d5965b4b9dd46582db1178d169c6bc465b0d6ff9ca3928fef5b9ae4e418fc15e83ebea0f87fa9ff5eed70050ded2849f47bf959d956850ce929851f0d8115f635b105ee2e4e15d04b2454bf6f4fadf034b10403119cd8e3b92fcc5b";
279   if (!strcasecmp(prime, goodPrime)) {

Na, wrth gwrs mae'n dal i fod yno rhai Mae profion ar gyfer primoldeb rhif, ond yn bersonol nid oes gennyf wybodaeth ddigonol o fathemateg bellach.

Iawn, cawsom y prif allwedd. I fewngofnodi, h.y. anfon ceisiadau, mae angen i chi berfformio amgryptio pellach, gan ddefnyddio AES.

Diffinnir yr allwedd neges fel 128 darn canol SHA256 y corff neges (gan gynnwys y sesiwn, ID y neges, ac ati), gan gynnwys y beit padin, wedi'i ragpendilio gan 32 beit a gymerwyd o'r allwedd awdurdodi.

Vasily, [22.06.18 14:08] Cyfartaledd, ast, darnau

Derbyniwyd auth_key. I gyd. Y tu hwnt iddynt... nid yw'n glir o'r ddogfen. Mae croeso i chi astudio'r cod ffynhonnell agored.

Sylwch fod angen rhwng 2.0 a 12 beit o badin ar MTProto 1024, yn dal i fod yn amodol ar yr amod bod hyd y neges sy'n deillio o hyn yn cael ei rannu â 16 beit.

Felly faint o padin ddylech chi ei ychwanegu?

Ac oes, mae yna hefyd 404 rhag ofn y bydd gwall

Os oedd unrhyw un wedi astudio'r diagram a thestun y ddogfennaeth yn ofalus, fe sylwon nhw nad oes MAC yno. A bod AES yn cael ei ddefnyddio mewn modd IGE penodol nad yw'n cael ei ddefnyddio yn unman arall. Maen nhw, wrth gwrs, yn ysgrifennu am hyn yn eu Cwestiynau Cyffredin... Yma, fel, allwedd y neges ei hun hefyd yw stwnsh SHA y data dadgryptio, a ddefnyddir i wirio cywirdeb - ac mewn achos o ddiffyg cyfatebiaeth, y ddogfennaeth am ryw reswm yn argymell eu hanwybyddu yn dawel (ond beth am ddiogelwch, beth os ydynt yn ein torri ni?).

Dydw i ddim yn cryptograffydd, efallai nad oes dim o'i le ar y modd hwn yn yr achos hwn o safbwynt damcaniaethol. Ond gallaf enwi problem ymarferol yn glir, gan ddefnyddio Telegram Desktop fel enghraifft. Mae'n amgryptio'r storfa leol (y rhain i gyd D877F783D5D3EF8C) yn yr un modd â negeseuon yn MTProto (dim ond yn yr achos hwn fersiwn 1.0), h.y. yn gyntaf y neges allweddol, yna y data ei hun (a rhywle o'r neilltu y prif mawr auth_key 256 bytes, heb ba rai msg_key ddiwerth). Felly, daw'r broblem yn amlwg ar ffeiliau mawr. Sef, mae angen i chi gadw dau gopi o'r data - wedi'u hamgryptio a'u dadgryptio. Ac os oes megabeit, neu ffrydio fideo, er enghraifft?.. Mae cynlluniau clasurol gyda MAC ar ôl y ciphertext yn caniatáu ichi ei ddarllen yn ffrwd, gan ei drosglwyddo ar unwaith. Ond gyda MTProto bydd yn rhaid i chi i ddechrau amgryptio neu ddadgryptio'r neges gyfan, dim ond wedyn ei throsglwyddo i'r rhwydwaith neu i ddisg. Felly, yn y fersiynau diweddaraf o Telegram Desktop yn y storfa yn user_data Defnyddir fformat arall hefyd - gydag AES yn y modd CTR.

Vasily, [21.06.18 01:27] O, darganfyddais beth yw IGE: IGE oedd yr ymgais gyntaf ar “ddelw amgryptio dilysu,” yn wreiddiol ar gyfer Kerberos. Roedd yn ymgais aflwyddiannus (nid yw'n darparu amddiffyniad cyfanrwydd), a bu'n rhaid ei ddileu. Dyna oedd dechrau cwest 20 mlynedd am fodd amgryptio dilysu sy'n gweithio, a arweiniodd yn ddiweddar at foddau fel OCB a GCM.

Ac yn awr y dadleuon o ochr y drol:

Mae'r tîm y tu ôl i Telegram, dan arweiniad Nikolai Durov, yn cynnwys chwe phencampwr ACM, hanner ohonynt yn Ph.Ds mewn mathemateg. Cymerodd tua dwy flynedd iddynt gyflwyno'r fersiwn gyfredol o MTProto.

Mae hynny'n ddoniol. Dwy flynedd ar y lefel is

Neu fe allech chi gymryd tls

Iawn, gadewch i ni ddweud ein bod ni wedi gwneud yr amgryptio a naws eraill. A yw'n bosibl o'r diwedd anfon ceisiadau wedi'u cyfresi yn TL a dad-gyfresi'r ymatebion? Felly beth ddylech chi ei anfon a sut? Yma, gadewch i ni ddweud, y dull initCysylltiad, efallai mai dyma fe?

Vasily, [25.06.18 18:46] Yn cychwyn cysylltiad ac yn arbed gwybodaeth ar ddyfais a chymhwysiad y defnyddiwr.

Mae'n derbyn app_id, device_model, system_version, app_version a lang_code.

A rhywfaint o ymholiad

Dogfennaeth fel bob amser. Mae croeso i chi astudio'r ffynhonnell agored

Os oedd popeth bron yn glir gydag invokeWithLayer, yna beth sydd o'i le yma? Mae'n troi allan, gadewch i ni ddweud bod gennym ni - roedd gan y cleient rywbeth i ofyn i'r gweinydd amdano eisoes - mae yna gais yr oeddem am ei anfon:

Vasily, [25.06.18 19:13] A barnu yn ôl y cod, mae'r alwad gyntaf wedi'i lapio yn y crap hwn, ac mae'r crap ei hun wedi'i lapio mewn invokewithlayer

Pam na allai initConnection fod yn alwad ar wahân, ond rhaid iddo fod yn ddeunydd lapio? Oes, fel y digwyddodd, rhaid ei wneud bob tro ar ddechrau pob sesiwn, ac nid unwaith, fel gyda'r prif allwedd. Ond! Ni all defnyddiwr anawdurdodedig ei alw! Nawr rydym wedi cyrraedd y cam lle mae'n berthnasol Yr un yma tudalen ddogfennaeth - ac mae'n dweud wrthym fod...

Dim ond cyfran fach o'r dulliau API sydd ar gael i ddefnyddwyr anawdurdodedig:

  • auth.sendCode
  • auth.resendCode
  • cyfrif.getPassword
  • auth.checkPassword
  • auth.checkPhone
  • awdurdod.signUp
  • awdurdod.signIn
  • auth.importAwdurdodi
  • help.getConfig
  • help.getNearestDc
  • help.getAppUpdate
  • help.getCdnConfig
  • langpack.getLangPack
  • langpack.getStrings
  • langpack.getGwahaniaeth
  • langpack.getIeithoedd
  • langpack.getIaith

Y cyntaf un ohonyn nhw, auth.sendCode, ac mae'r cais cyntaf annwyl hwnnw lle rydym yn anfon api_id ac api_hash, ac ar ôl hynny rydym yn derbyn SMS gyda chod. Ac os ydym yn y DC anghywir (mae rhifau ffôn yn y wlad hon yn cael eu gwasanaethu gan un arall, er enghraifft), yna byddwn yn derbyn gwall gyda rhif y DC a ddymunir. I ddarganfod pa gyfeiriad IP yn ôl rhif DC y mae angen i chi gysylltu ag ef, helpwch ni help.getConfig. Ar un adeg dim ond 5 cais oedd, ond ar ôl digwyddiadau enwog 2018, mae'r nifer wedi cynyddu'n sylweddol.

Nawr, gadewch i ni gofio ein bod wedi cyrraedd y cam hwn ar y gweinydd yn ddienw. Onid yw'n rhy ddrud i gael cyfeiriad IP yn unig? Beth am wneud hyn, a gweithrediadau eraill, yn y rhan o MTProto sydd heb ei hamgryptio? Rwy’n clywed y gwrthwynebiad: “sut allwn ni wneud yn siŵr nad RKN fydd yn ymateb gyda chyfeiriadau ffug?” I hyn rydym yn cofio bod, yn gyffredinol, swyddogol cleientiaid Mae allweddi RSA wedi'u mewnosod, h.y. allwch chi jyst i arwyddo y wybodaeth hon. Mewn gwirionedd, mae hyn eisoes yn cael ei wneud ar gyfer gwybodaeth am osgoi blocio y mae cleientiaid yn ei dderbyn trwy sianeli eraill (yn rhesymegol, ni ellir gwneud hyn yn MTProto ei hun; mae angen i chi hefyd wybod ble i gysylltu).

IAWN. Ar y cam hwn o awdurdodi cleient, nid ydym wedi'n hawdurdodi eto ac nid ydym wedi cofrestru ein cais. Rydyn ni eisiau gweld am y tro beth mae'r gweinydd yn ymateb i ddulliau sydd ar gael i ddefnyddiwr anawdurdodedig. Ac yma…

Vasily, [10.07.18 14:45] https://core.telegram.org/method/help.getConfig

config#7dae33e0 [...] = Config;
help.getConfig#c4f9186b = Config;

https://core.telegram.org/api/datacenter

config#232d5905 [...] = Config;
help.getConfig#c4f9186b = Config;

Yn y cynllun, y cyntaf sy'n dod yn ail

Yn y sgema penbwrdd y trydydd gwerth yw

Ydy, ers hynny, wrth gwrs, mae'r ddogfennaeth wedi'i diweddaru. Er efallai y bydd yn dod yn amherthnasol eto. Sut ddylai datblygwr dibrofiad wybod? Efallai os byddwch yn cofrestru eich cais, y byddant yn rhoi gwybod i chi? Gwnaeth Vasily hyn, ond gwaetha'r modd, ni wnaethant anfon unrhyw beth ato (eto, byddwn yn siarad am hyn yn yr ail ran).

...Fe wnaethoch chi sylwi ein bod ni rywsut eisoes wedi symud i'r API, h.y. i'r lefel nesaf, a methu rhywbeth yn y pwnc MTProto? Dim syndod:

Vasily, [28.06.18 02:04] Mm, maen nhw'n chwilota trwy rai o'r algorithmau ar e2e

Mae Mtproto yn diffinio algorithmau amgryptio ac allweddi ar gyfer y ddau barth, yn ogystal ag ychydig o strwythur lapio

Ond maen nhw'n cymysgu lefelau gwahanol o'r pentwr yn gyson, felly nid yw bob amser yn glir ble daeth mtproto i ben a dechreuodd y lefel nesaf

Sut maen nhw'n cymysgu? Wel, dyma'r un allwedd dros dro ar gyfer PFS, er enghraifft (gyda llaw, ni all Telegram Desktop ei wneud). Fe'i gweithredir gan gais API auth.bindTempAuthKey, h.y. o'r lefel uchaf. Ond ar yr un pryd mae'n ymyrryd ag amgryptio ar y lefel is - ar ei ôl, er enghraifft, mae angen i chi ei wneud eto initConnection ac ati, nid yw hyn yn yn unig cais arferol. Yr hyn sydd hefyd yn arbennig yw y gallwch chi gael UN allwedd dros dro yn unig fesul DC, er bod y maes auth_key_id ym mhob neges yn caniatáu ichi newid yr allwedd o leiaf bob neges, a bod gan y gweinydd yr hawl i “anghofio” yr allwedd dros dro ar unrhyw adeg - nid yw'r ddogfennaeth yn dweud beth i'w wneud yn yr achos hwn... wel, pam y gellid Nid oes gennych chi sawl allwedd, fel gyda set o halwynau'r dyfodol, a ?..

Mae yna ychydig o bethau eraill sy'n werth eu nodi am y thema MTProto.

Negeseuon neges, msg_id, msg_seqno, cadarnhad, pings i'r cyfeiriad anghywir a hynodion eraill

Pam mae angen i chi wybod amdanynt? Oherwydd eu bod yn “gollwng” i lefel uwch, ac mae angen i chi fod yn ymwybodol ohonynt wrth weithio gyda'r API. Gadewch i ni dybio nad oes gennym ddiddordeb mewn msg_key; mae'r lefel is wedi dadgryptio popeth i ni. Ond y tu mewn i'r data dadgryptio mae gennym y meysydd canlynol (hefyd hyd y data, felly rydyn ni'n gwybod ble mae'r padin, ond nid yw hynny'n bwysig):

  • halen - int64
  • session_id - int64
  • message_id — int64
  • seq_no - int32

Gadewch inni eich atgoffa mai dim ond un halen sydd ar gyfer y DC cyfan. Pam gwybod amdani? Nid yn unig oherwydd bod cais get_future_salts, sy'n dweud wrthych pa gyfyngau fydd yn ddilys, ond hefyd oherwydd os yw'ch halen yn “pydru”, yna bydd y neges (cais) yn syml yn cael ei golli. Bydd y gweinydd, wrth gwrs, yn adrodd am yr halen newydd trwy gyhoeddi new_session_created - ond gyda'r hen un bydd yn rhaid i chi ei ail-anfon rhywsut, er enghraifft. Ac mae'r mater hwn yn effeithio ar bensaernïaeth y cais.

Caniateir i'r gweinydd ollwng sesiynau yn gyfan gwbl ac ymateb yn y modd hwn am lawer o resymau. A dweud y gwir, beth yw sesiwn MTProto o ochr y cleient? Dyma ddau rif session_id и seq_no negeseuon o fewn y sesiwn hon. Wel, a'r cysylltiad TCP gwaelodol, wrth gwrs. Gadewch i ni ddweud nad yw ein cleient yn gwybod sut i wneud llawer o bethau o hyd, fe ddatgysylltu ac ailgysylltu. Pe bai hyn yn digwydd yn gyflym - parhaodd yr hen sesiwn yn y cysylltiad TCP newydd, cynyddu seq_no ymhellach. Os yw'n cymryd amser hir, gallai'r gweinydd ei ddileu, oherwydd ar ei ochr mae hefyd yn giw, fel y cawsom wybod.

Beth ddylai fod seq_no? O, dyna gwestiwn dyrys. Ceisiwch ddeall yn onest beth a olygwyd:

Neges sy'n Gysylltiedig â Chynnwys

Neges sy'n gofyn am gydnabyddiaeth benodol. Mae'r rhain yn cynnwys yr holl negeseuon defnyddwyr a llawer o negeseuon gwasanaeth, bron pob un ac eithrio cynwysyddion a chydnabyddiaethau.

Rhif Dilyniant Neges (msg_seqno)

Rhif 32-did sy'n hafal i ddwywaith nifer y negeseuon “cysylltiedig â chynnwys” (y rhai sydd angen cydnabyddiaeth, ac yn arbennig y rhai nad ydynt yn gynwysyddion) a grëwyd gan yr anfonwr cyn y neges hon ac a gynyddwyd wedyn gan un os yw'r neges gyfredol yn un neges sy'n ymwneud â chynnwys. Mae cynhwysydd bob amser yn cael ei gynhyrchu ar ôl ei gynnwys cyfan; felly, mae ei rif dilyniant yn fwy neu'n hafal i rifau dilyniant y negeseuon sydd ynddo.

Pa fath o syrcas yw hon gyda chynyddiad o 1, ac yna un arall erbyn 2?.. Rwy'n amau ​​​​i ddechrau eu bod yn golygu "y darn lleiaf arwyddocaol i ACK, mae'r gweddill yn rhif", ond nid yw'r canlyniad yn union yr un peth - yn enwedig, mae'n dod allan, gellir ei anfon rhai cadarnhad yn cael yr un peth seq_no! Sut? Wel, er enghraifft, mae'r gweinydd yn anfon rhywbeth atom, yn ei anfon, ac rydym ni ein hunain yn aros yn dawel, dim ond yn ymateb gyda negeseuon gwasanaeth yn cadarnhau derbyn ei negeseuon. Yn yr achos hwn, bydd gan ein cadarnhadau sy'n mynd allan yr un nifer sy'n mynd allan. Os ydych chi'n gyfarwydd â TCP ac yn meddwl bod hyn yn swnio'n wyllt rywsut, ond nid yw'n ymddangos yn wyllt iawn, oherwydd yn TCP seq_no nid yw'n newid, ond mae cadarnhad yn mynd i seq_no ar yr ochr arall, byddaf yn prysuro i'ch cynhyrfu. Darperir cadarnhad yn MTProto NID ar seq_no, fel yn TCP, ond erbyn msg_id !

Beth yw hwn msg_id, y pwysicaf o'r meysydd hyn? Dynodwr neges unigryw, fel mae'r enw'n awgrymu. Fe'i diffinnir fel rhif 64-did, y mae gan y darnau isaf ohonynt yr hud “gweinydd-nid-gweinydd” eto, ac mae'r gweddill yn stamp amser Unix, gan gynnwys y rhan ffracsiynol, wedi'i symud 32 did i'r chwith. Y rhai. stamp amser per se (a bydd negeseuon ag amseroedd sy'n amrywio gormod yn cael eu gwrthod gan y gweinydd). O hyn mae'n ymddangos bod hwn yn gyffredinol yn ddynodwr sy'n fyd-eang i'r cleient. O ystyried hynny - gadewch i ni gofio session_id - rydym yn sicr: Ni ellir o dan unrhyw amgylchiadau anfon neges a olygir ar gyfer un sesiwn i sesiwn wahanol. Hynny yw, mae'n troi allan bod yna eisoes 3 lefel - sesiwn, rhif sesiwn, id neges. Pam gorgymhlethdod o'r fath, mae'r dirgelwch hwn yn fawr iawn.

Felly, msg_id ei angen ar gyfer...

RPC: ceisiadau, ymatebion, gwallau. Cadarnhadau.

Fel y gallech fod wedi sylwi, nid oes unrhyw fath neu swyddogaeth "gwneud cais RPC" arbennig yn unrhyw le yn y diagram, er bod atebion. Wedi'r cyfan, mae gennym negeseuon sy'n ymwneud â chynnwys! Hynny yw, unrhyw gallai'r neges fod yn gais! Neu i beidio â bod. Wedi'r cyfan, yr un mae msg_id. Ond mae yna atebion:

rpc_result#f35c6d01 req_msg_id:long result:Object = RpcResult;

Dyma lle nodir pa neges y mae hwn yn ymateb iddi. Felly, ar lefel uchaf yr API, bydd yn rhaid ichi gofio beth oedd nifer eich cais - credaf nad oes angen egluro bod y gwaith yn anghydamserol, a gall fod sawl cais ar y gweill ar yr un pryd, y gellir dychwelyd yr atebion iddynt mewn unrhyw drefn? Mewn egwyddor, o hyn a negeseuon gwall fel dim gweithwyr, gellir olrhain y bensaernïaeth y tu ôl i hyn: mae'r gweinydd sy'n cynnal cysylltiad TCP â chi yn gydbwysydd pen blaen, mae'n anfon ceisiadau ymlaen at yr ôl-wynebau ac yn eu casglu'n ôl trwy message_id. Mae'n ymddangos bod popeth yma yn glir, yn rhesymegol ac yn dda.

Ydw?.. Ac os ydych chi'n meddwl amdano? Wedi'r cyfan, mae gan yr ymateb RPC ei hun faes hefyd msg_id! A oes angen i ni weiddi wrth y gweinydd “nid ydych yn ateb fy ateb!”? Ac ie, beth oedd yna am gadarnhadau? Am dudalen negeseuon am negeseuon yn dweud wrthym beth sydd

msgs_ack#62d6b459 msg_ids:Vector long = MsgsAck;

a rhaid ei wneyd gan bob ochr. Ond nid bob amser! Os cawsoch RpcResult, mae ei hun yn gadarnhad. Hynny yw, gall y gweinydd ymateb i'ch cais gyda MsgsAck - fel, “Fe wnes i ei dderbyn.” Gall RpcResult ymateb ar unwaith. Gallai fod y ddau.

Ac ie, mae'n rhaid i chi ateb yr ateb o hyd! Cadarnhad. Fel arall, bydd y gweinydd yn ei ystyried yn anghyflawn ac yn ei anfon yn ôl atoch eto. Hyd yn oed ar ôl ailgysylltu. Ond yma, wrth gwrs, mae mater seibiannau yn codi. Gadewch i ni edrych arnynt ychydig yn ddiweddarach.

Yn y cyfamser, gadewch i ni edrych ar wallau gweithredu ymholiad posibl.

rpc_error#2144ca19 error_code:int error_message:string = RpcError;

O, bydd rhywun yn exclaim, dyma fformat mwy trugarog - mae llinell! Cymerwch eich amser. Yma rhestr o wallau, ond wrth gwrs ddim yn gyflawn. Oddiwrtho fe ddysgwn fod y cod rhywbeth tebyg Gwallau HTTP (wel, wrth gwrs, nid yw semanteg yr ymatebion yn cael eu parchu, mewn rhai mannau maent yn cael eu dosbarthu ar hap ymhlith y codau), ac mae'r llinell yn edrych fel CAPITAL_LETERS_AND_NUMBERS. Er enghraifft, PHONE_NUMBER_OCCUPIED neu FILE_PART_Х_MISSING. Wel, hynny yw, bydd angen y llinell hon arnoch o hyd dosran. Er enghraifft FLOOD_WAIT_3600 yn golygu bod yn rhaid i chi aros am awr, a PHONE_MIGRATE_5, bod yn rhaid cofrestru rhif ffôn gyda'r rhagddodiad hwn yn y 5ed DC. Mae gennym iaith fath, iawn? Nid oes angen dadl o linyn arnom, bydd rhai rheolaidd yn ei wneud, iawn.

Unwaith eto, nid yw hyn ar y dudalen negeseuon gwasanaeth, ond, fel sy'n arferol eisoes gyda'r prosiect hwn, gellir dod o hyd i'r wybodaeth ar dudalen ddogfennaeth arall. Neu bwrw amheuaeth. Yn gyntaf, edrychwch, teipio / torri haen - RpcError gellir ei nythu i mewn RpcResult. Pam ddim tu allan? Beth na wnaethom ei gymryd i ystyriaeth?.. Yn unol â hynny, ble mae'r warant hynny RpcError efallai NAD yw wedi'i ymgorffori yn RpcResult, ond bod yn uniongyrchol neu wedi nythu mewn math arall?.. Ac os na all, pam nad yw ar y lefel uchaf, h.y. mae ar goll req_msg_id ? ..

Ond gadewch i ni barhau am negeseuon gwasanaeth. Efallai y bydd y cleient yn meddwl bod y gweinydd yn meddwl am amser hir ac yn gwneud y cais gwych hwn:

rpc_drop_answer#58e4a740 req_msg_id:long = RpcDropAnswer;

Mae tri ateb posibl i’r cwestiwn hwn, sydd eto’n croestorri â’r mecanwaith cadarnhau; ceisio deall beth ddylent fod (a beth yw’r rhestr gyffredinol o fathau nad oes angen eu cadarnhau) yn cael ei adael i’r darllenydd fel gwaith cartref (sylwer: y wybodaeth yn nid yw cod ffynhonnell Telegram Desktop yn gyflawn).

Caethiwed i gyffuriau: statws neges

Yn gyffredinol, mae llawer o leoedd yn TL, MTProto a Telegram yn gyffredinol yn gadael teimlad o ystyfnigrwydd, ond allan o gwrteisi, tact ac eraill sgiliau meddal Fe wnaethom gadw'n dawel yn ei gylch yn gwrtais, a sensro'r anweddusrwydd yn y deialogau. Fodd bynnag, y lle hwnОy rhan fwyaf o'r dudalen yn ymwneud negeseuon am negeseuon Mae'n syfrdanol hyd yn oed i mi, sydd wedi bod yn gweithio gyda phrotocolau rhwydwaith ers amser maith ac sydd wedi gweld beiciau o wahanol raddau o gam.

Mae'n dechrau'n ddiniwed, gyda chadarnhadau. Nesaf maen nhw'n dweud wrthym ni

bad_msg_notification#a7eff811 bad_msg_id:long bad_msg_seqno:int error_code:int = BadMsgNotification;
bad_server_salt#edab447b bad_msg_id:long bad_msg_seqno:int error_code:int new_server_salt:long = BadMsgNotification;

Wel, bydd yn rhaid i bawb sy'n dechrau gweithio gyda MTProto ddelio â nhw; yn y cylch “cywiro - ail-grynhoi - lansio”, mae cael gwallau rhif neu halen sydd wedi llwyddo i fynd yn ddrwg yn ystod golygiadau yn beth cyffredin. Fodd bynnag, mae dau bwynt yma:

  1. Mae hyn yn golygu bod y neges wreiddiol yn cael ei cholli. Mae angen i ni greu rhai ciwiau, byddwn yn edrych ar hynny yn nes ymlaen.
  2. Beth yw'r rhifau gwall rhyfedd hyn? 16, 17, 18, 19, 20, 32, 33, 34, 35, 48, 64... ble mae'r rhifau eraill, Tommy?

Mae’r ddogfennaeth yn nodi:

Y bwriad yw bod gwerthoedd error_code yn cael eu grwpio (error_code >> 4): er enghraifft, mae'r codau 0x40 - 0x4f yn cyfateb i wallau mewn dadelfeniad cynhwysydd.

ond, yn gyntaf, symudiad i’r cyfeiriad arall, ac yn ail, does dim ots, ble mae’r codau eraill? Ym mhen yr awdur?.. Fodd bynnag, trifles yw'r rhain.

Mae caethiwed yn dechrau mewn negeseuon am statws negeseuon a chopïau neges:

  • Cais am Wybodaeth Statws Neges
    Os nad yw’r naill barti neu’r llall wedi derbyn gwybodaeth am statws ei negeseuon sy’n mynd allan ers tro, gall ofyn yn benodol amdani gan y parti arall:
    msgs_state_req#da69fb52 msg_ids:Vector long = MsgsStateReq;
  • Neges Wybodaeth am Statws Negeseuon
    msgs_state_info#04deb57d req_msg_id:long info:string = MsgsStateInfo;
    Yma, info yn llinyn sy'n cynnwys union un beit o statws neges ar gyfer pob neges o'r rhestr msg_ids sy'n dod i mewn:

    • 1 = dim byd yn hysbys am y neges (msg_id yn rhy isel, efallai bod y parti arall wedi ei anghofio)
    • 2 = neges heb ei derbyn (mae msg_id yn dod o fewn yr ystod o ddynodwyr sydd wedi'u storio; fodd bynnag, yn sicr nid yw'r parti arall wedi derbyn neges o'r fath)
    • 3 = neges heb ei derbyn (msg_id yn rhy uchel; fodd bynnag, yn sicr nid yw'r parti arall wedi ei dderbyn eto)
    • 4 = neges a dderbyniwyd (sylwch fod yr ymateb hwn hefyd ar yr un pryd yn gydnabyddiaeth derbyn)
    • +8 = neges wedi ei chydnabod yn barod
    • +16 = neges ddim angen cydnabyddiaeth
    • +32 = Ymholiad RPC yn y neges yn cael ei phrosesu neu ei phrosesu eisoes wedi ei chwblhau
    • +64 = ymateb sy'n ymwneud â chynnwys i'r neges a gynhyrchwyd eisoes
    • +128 = mae parti arall yn gwybod am ffaith bod neges wedi ei derbyn yn barod
      Nid oes angen cydnabod yr ymateb hwn. Mae'n gydnabyddiaeth o'r msgs_state_req perthnasol, ynddo'i hun.
      Sylwch, os daw'n sydyn nad oes gan y parti arall neges sy'n edrych fel ei bod wedi'i hanfon ato, yn syml iawn y gellir ail-anfon y neges. Hyd yn oed os dylai'r parti arall dderbyn dau gopi o'r neges ar yr un pryd, bydd y copi dyblyg yn cael ei anwybyddu. (Os oes gormod o amser wedi mynd heibio, a'r msg_id gwreiddiol ddim yn ddilys bellach, mae'r neges i'w lapio mewn msg_copy).
  • Cyfathrebu Statws Negeseuon yn Wirfoddol
    Gall y naill barti neu'r llall hysbysu'r parti arall o'u gwirfodd am statws y negeseuon a drosglwyddir gan y parti arall.
    msgs_all_info#8cc0d131 msg_ids:Vector long info:string = MsgsAllInfo
  • Cyfathrebu Gwirfoddol Estynedig o Statws Un Neges
    ...
    msg_detailed_info#276d3ec6 msg_id:long answer_msg_id:long bytes:int status:int = MsgDetailedInfo;
    msg_new_detailed_info#809db6df answer_msg_id:long bytes:int status:int = MsgDetailedInfo;
  • Cais Penodol i Ail-Anfon Negeseuon
    msg_resend_req#7d861a08 msg_ids:Vector long = MsgResendReq;
    Mae'r parti anghysbell yn ymateb ar unwaith trwy ail-anfon y negeseuon y gofynnwyd amdanynt […]
  • Cais Penodol i AilAnfon Atebion
    msg_resend_ans_req#8610baeb msg_ids:Vector long = MsgResendReq;
    Mae'r parti anghysbell yn ymateb ar unwaith trwy ail-anfon atebion at y negeseuon y gofynnwyd amdanynt […]
  • Copïau Neges
    Mewn rhai sefyllfaoedd, mae angen ail-anfon hen neges gyda msg_id nad yw'n ddilys bellach. Yna, caiff ei lapio mewn cynhwysydd copi:
    msg_copy#e06046b2 orig_message:Message = MessageCopy;
    Ar ôl ei derbyn, caiff y neges ei phrosesu fel pe na bai'r deunydd lapio yno. Fodd bynnag, os yw'n hysbys i sicrwydd bod y neges orig_message.msg_id wedi'i derbyn, yna nid yw'r neges newydd yn cael ei phrosesu (tra ar yr un pryd, mae hi ac orig_message.msg_id yn cael eu cydnabod). Rhaid i werth orig_message.msg_id fod yn is na msg_id y cynhwysydd.

Gadewch i ni hyd yn oed gadw'n dawel am beth msgs_state_info eto mae clustiau'r TL anorffenedig yn sticio allan (roedd angen fector o beit, ac yn y ddau did isaf roedd enum, ac yn y ddau did uwch roedd baneri). Mae'r pwynt yn wahanol. A oes unrhyw un yn deall pam mae hyn i gyd yn ymarferol? mewn cleient go iawn angenrheidiol?.. Gydag anhawster, ond gellir dychmygu rhywfaint o fudd os yw person yn ymwneud â dadfygio, ac mewn modd rhyngweithiol - gofynnwch i'r gweinydd beth a sut. Ond yma disgrifir y ceisiadau taith gron.

Mae'n dilyn bod yn rhaid i bob parti nid yn unig amgryptio ac anfon negeseuon, ond hefyd storio data amdanynt eu hunain, am yr ymatebion iddynt, am gyfnod anhysbys o amser. Nid yw'r ddogfennaeth yn disgrifio amseriadau na chymhwysedd ymarferol y nodweddion hyn. mewn unrhyw ffordd. Yr hyn sydd fwyaf rhyfeddol yw eu bod yn cael eu defnyddio mewn gwirionedd yn y cod o gleientiaid swyddogol! Mae'n debyg y dywedwyd wrthynt am rywbeth nad oedd wedi'i gynnwys yn y dogfennau cyhoeddus. Deall o'r cod pam, nid yw bellach mor syml ag yn achos TL - nid yw'n rhan (gymharol) wedi'i hynysu'n rhesymegol, ond yn ddarn sy'n gysylltiedig â phensaernïaeth y cais, h.y. bydd angen llawer mwy o amser i ddeall cod y cais.

Pings ac amseriadau. ciwiau.

O bopeth, os cofiwn y dyfalu am bensaernïaeth y gweinydd (dosbarthiad ceisiadau ar draws backends), mae peth trist yn dilyn - er gwaethaf yr holl warantau cyflenwi yn TCP (naill ai mae'r data'n cael ei gyflwyno, neu fe'ch hysbysir am y bwlch, ond bydd y data'n cael ei gyflwyno cyn i'r broblem ddigwydd), bod cadarnhad yn MTProto ei hun - dim gwarantau. Gall y gweinydd golli neu daflu eich neges yn hawdd, ac ni ellir gwneud dim amdano, dim ond defnyddio gwahanol fathau o faglau.

Ac yn gyntaf oll - ciwiau neges. Wel, gydag un peth roedd popeth yn amlwg o'r cychwyn cyntaf - rhaid storio neges heb ei chadarnhau a digio. Ac ar ôl faint o amser? Ac mae'r cellwair yn ei adnabod. Efallai bod y negeseuon gwasanaeth caeth hynny rywsut yn datrys y broblem hon gyda baglau, dyweder, yn Telegram Desktop mae tua 4 ciw yn cyfateb iddynt (efallai yn fwy, fel y crybwyllwyd eisoes, ar gyfer hyn mae angen i chi ymchwilio i'w god a'i bensaernïaeth yn fwy difrifol; ar yr un peth amser, rydym yn gwybod na ellir ei gymryd fel sampl; ni ​​ddefnyddir nifer penodol o fathau o'r cynllun MTProto ynddo).

Pam fod hyn yn digwydd? Yn ôl pob tebyg, nid oedd y rhaglenwyr gweinydd yn gallu sicrhau dibynadwyedd o fewn y clwstwr, na hyd yn oed byffro ar y balancer blaen, a throsglwyddo'r broblem hon i'r cleient. Allan o anobaith, ceisiodd Vasily weithredu opsiwn amgen, gyda dim ond dau giw, gan ddefnyddio algorithmau o TCP - mesur yr RTT i'r gweinydd ac addasu maint y "ffenestr" (mewn negeseuon) yn dibynnu ar nifer y ceisiadau heb eu cadarnhau. Hynny yw, hewristig mor arw ar gyfer asesu llwyth y gweinydd yw faint o'n ceisiadau y gall eu cnoi ar yr un pryd a pheidio â'u colli.

Wel, hynny yw, rydych chi'n deall, iawn? Os oes rhaid i chi weithredu TCP eto ar ben protocol sy'n rhedeg dros TCP, mae hyn yn dynodi protocol sydd wedi'i ddylunio'n wael iawn.

O ie, pam mae angen mwy nag un ciw arnoch chi, a beth mae hyn yn ei olygu i berson sy'n gweithio gydag API lefel uchel beth bynnag? Edrychwch, rydych chi'n gwneud cais, yn ei gyfresoli, ond yn aml ni allwch ei anfon ar unwaith. Pam? Oherwydd bydd yr ateb msg_id, sydd dros droаLabel ydw i, ac mae'n well gohirio'r aseiniad tan mor hwyr â phosib - rhag ofn i'r gweinydd ei wrthod oherwydd diffyg cyfatebiaeth amser rhyngom ni ac ef (wrth gwrs, gallwn wneud bagl sy'n symud ein hamser o'r presennol i'r gweinydd trwy ychwanegu delta wedi'i gyfrifo o ymatebion y gweinydd - mae cleientiaid swyddogol yn gwneud hyn, ond mae'n amrwd ac yn anghywir oherwydd byffro). Felly, pan fyddwch chi'n gwneud cais gyda galwad swyddogaeth leol o'r llyfrgell, mae'r neges yn mynd trwy'r camau canlynol:

  1. Mae'n gorwedd mewn un ciw ac yn aros am amgryptio.
  2. Penodwyd msg_id ac aeth y neges i giw arall - blaenyrru posib; anfon at y soced.
  3. a) Ymatebodd y gweinydd MsgsAck - danfonwyd y neges, rydym yn ei dileu o'r “ciw arall”.
    b) Neu i’r gwrthwyneb, nid oedd yn hoffi rhywbeth, atebodd badmsg - ail-anfon o “ciw arall”
    c) Dim byd yn hysbys, mae angen digio'r neges o giw arall - ond ni wyddys pryd yn union.
  4. Ymatebodd y gweinydd o'r diwedd RpcResult - yr ymateb (neu'r gwall) gwirioneddol - nid yn unig wedi'i gyflwyno, ond hefyd wedi'i brosesu.

Efallai y, gallai'r defnydd o gynwysyddion ddatrys y broblem yn rhannol. Dyma pryd mae criw o negeseuon yn cael eu pacio i mewn i un, ac ymatebodd y gweinydd gyda chadarnhad i bob un ohonynt ar unwaith, mewn un msg_id. Ond bydd hefyd yn gwrthod y pecyn hwn, os aeth rhywbeth o'i le, yn ei gyfanrwydd.

Ac ar y pwynt hwn daw ystyriaethau annhechnegol i rym. O brofiad, rydym wedi gweld llawer o faglau, ac yn ogystal, byddwn yn awr yn gweld mwy o enghreifftiau o gyngor gwael a phensaernïaeth - mewn amodau o'r fath, a yw'n werth ymddiried a gwneud penderfyniadau o'r fath? Rhethregol yw'r cwestiwn (nid wrth gwrs).

Am beth rydyn ni'n siarad? Os ar bwnc “negeseuon cyffuriau am negeseuon” gallwch chi ddyfalu o hyd gyda gwrthwynebiadau fel “rydych chi'n dwp, doeddech chi ddim yn deall ein cynllun gwych!” (felly ysgrifennwch y ddogfennaeth yn gyntaf, fel y dylai pobl arferol, gyda rhesymeg ac enghreifftiau o gyfnewid pecynnau, yna byddwn yn siarad), yna mae amseriadau / seibiannau yn gwestiwn cwbl ymarferol a phenodol, mae popeth yma wedi bod yn hysbys ers amser maith. Beth mae'r ddogfennaeth yn ei ddweud wrthym am seibiannau?

Mae gweinydd fel arfer yn cydnabod derbyn neges gan gleient (ymholiad RPC fel arfer) gan ddefnyddio ymateb RPC. Os bydd ymateb yn hir yn dod, gall gweinydd anfon cydnabyddiaeth derbynneb yn gyntaf, ac ychydig yn ddiweddarach, ymateb RPC ei hun.

Mae cleient fel arfer yn cydnabod derbyn neges gan weinydd (fel arfer, ymateb RPC) trwy ychwanegu cydnabyddiaeth at yr ymholiad RPC nesaf os na chaiff ei drosglwyddo'n rhy hwyr (os caiff ei gynhyrchu, dyweder, 60-120 eiliad ar ôl ei dderbyn o neges gan y gweinydd). Fodd bynnag, os am gyfnod hir o amser nid oes unrhyw reswm i anfon negeseuon at y gweinydd neu os oes nifer fawr o negeseuon heb eu cydnabod gan y gweinydd (dyweder, dros 16), mae'r cleient yn trosglwyddo cydnabyddiaeth annibynnol.

... Rwy'n cyfieithu: nid ydym ni ein hunain yn gwybod faint a sut mae ei angen arnom, felly gadewch i ni gymryd yn ganiataol y bydd fel hyn.

Ac am pings:

Negeseuon Ping (PING/PONG)

ping#7abe77ec ping_id:long = Pong;

Fel arfer dychwelir ymateb i'r un cysylltiad:

pong#347773c5 msg_id:long ping_id:long = Pong;

Nid oes angen cydnabyddiaeth ar gyfer y negeseuon hyn. Dim ond mewn ymateb i ping y mae pong yn cael ei drosglwyddo tra bod modd cychwyn ping gan y naill ochr neu'r llall.

Cau Cysylltiad Gohiriedig + PING

ping_delay_disconnect#f3427b8c ping_id:long disconnect_delay:int = Pong;

Yn gweithio fel ping. Yn ogystal, ar ôl derbyn hyn, mae'r gweinydd yn cychwyn amserydd a fydd yn cau'r cysylltiad cyfredol disconnect_delay eiliadau yn ddiweddarach oni bai ei fod yn derbyn neges newydd o'r un math sy'n ailosod yr holl amseryddion blaenorol yn awtomatig. Os bydd y cleient yn anfon y pings hyn unwaith bob 60 eiliad, er enghraifft, gall osod disconnect_delay hafal i 75 eiliad.

Ydych chi'n wallgof?! Mewn 60 eiliad, bydd y trên yn mynd i mewn i'r orsaf, yn gollwng a chodi teithwyr, ac eto'n colli cysylltiad yn y twnnel. Mewn 120 eiliad, tra byddwch chi'n ei glywed, bydd yn cyrraedd un arall, a bydd y cysylltiad yn fwyaf tebygol o dorri. Wel, mae'n amlwg o ble mae'r coesau'n dod - “Clywais i ganu, ond ddim yn gwybod ble mae hi”, mae algorithm Nagl a'r opsiwn TCP_NODELAY, wedi'u bwriadu ar gyfer gwaith rhyngweithiol. Ond, esgusodwch fi, daliwch eich gafael ar ei werth rhagosodedig - 200 Millieiliadau Os ydych chi wir eisiau darlunio rhywbeth tebyg ac arbed cwpl o becynnau posib, yna gohiriwch ef am 5 eiliad, neu beth bynnag mae'r neges “Defnyddiwr yn teipio...” bellach wedi dod i ben. Ond dim mwy.

Ac yn olaf, pings. Hynny yw, gwirio bywiogrwydd y cysylltiad TCP. Mae'n ddoniol, ond tua 10 mlynedd yn ôl ysgrifennais destun beirniadol am negesydd dorm ein cyfadran - fe wnaeth yr awduron yno hefyd pingio'r gweinydd gan y cleient, ac nid i'r gwrthwyneb. Ond mae myfyrwyr y drydedd flwyddyn yn un peth, ac mae swyddfa ryngwladol yn beth arall, iawn?..

Yn gyntaf, ychydig o raglen addysgol. Gall cysylltiad TCP, yn absenoldeb cyfnewid pecynnau, fyw am wythnosau. Mae hyn yn dda ac yn ddrwg, yn dibynnu ar y pwrpas. Mae'n dda os oedd gennych chi gysylltiad SSH yn agored i'r gweinydd, fe wnaethoch chi godi o'r cyfrifiadur, ailgychwyn y llwybrydd, dychwelyd i'ch lle - ni chafodd y sesiwn trwy'r gweinydd hwn ei rhwygo (ni wnaethoch chi deipio unrhyw beth, nid oedd unrhyw becynnau) , mae'n gyfleus. Mae'n ddrwg os oes miloedd o gleientiaid ar y gweinydd, pob un yn defnyddio adnoddau (helo, Postgres!), Ac efallai bod gwesteiwr y cleient wedi ailgychwyn amser maith yn ôl - ond ni fyddwn yn gwybod amdano.

Mae systemau sgwrsio/IM yn perthyn i'r ail achos am un rheswm ychwanegol - statws ar-lein. Os “syrthiodd y defnyddiwr”, mae angen i chi roi gwybod i'w interlocutors am hyn. Fel arall, byddwch yn y pen draw â chamgymeriad a wnaeth crewyr Jabber (a'i gywiro am 20 mlynedd) - mae'r defnyddiwr wedi datgysylltu, ond maent yn parhau i ysgrifennu negeseuon ato, gan gredu ei fod ar-lein (a oedd hefyd ar goll yn llwyr yn y rhain ychydig funudau cyn i'r datgysylltiad gael ei ddarganfod). Na, ni fydd yr opsiwn TCP_KEEPALIVE, y mae llawer o bobl nad ydynt yn deall sut mae amseryddion TCP yn gweithio yn taflu i mewn ar hap (trwy osod gwerthoedd gwyllt fel degau o eiliadau), yn helpu yma - mae angen i chi wneud yn siŵr nad yn unig y cnewyllyn OS o beiriant y defnyddiwr yn fyw, ond hefyd yn gweithredu'n normal, yn gallu ymateb, a'r cais ei hun (ydych chi'n meddwl na all rewi? Rhewodd Telegram Desktop ar Ubuntu 18.04 i mi fwy nag unwaith).

Dyna pam mae'n rhaid i chi ping gweinydd cleient, ac nid i'r gwrthwyneb - os yw'r cleient yn gwneud hyn, os yw'r cysylltiad yn cael ei dorri, ni fydd y ping yn cael ei gyflwyno, ni fydd y nod yn cael ei gyflawni.

Beth rydyn ni'n ei weld ar Telegram? Mae'n union i'r gwrthwyneb! Wel, hynny yw. Yn ffurfiol, wrth gwrs, gall y ddwy ochr pingio ei gilydd. Yn ymarferol, mae cleientiaid yn defnyddio baglau ping_delay_disconnect, sy'n gosod yr amserydd ar y gweinydd. Wel, esgusodwch fi, nid mater i'r cleient yw penderfynu pa mor hir y mae am fyw yno heb ping. Mae'r gweinydd, yn seiliedig ar ei lwyth, yn gwybod yn well. Ond, wrth gwrs, os nad oes ots gennych chi am yr adnoddau, yna chi fydd eich Pinocchio drwg eich hun, a bydd bagl yn gwneud hynny...

Sut ddylai fod wedi cael ei ddylunio?

Credaf fod y ffeithiau uchod yn dangos yn glir nad yw cymhwysedd tîm Telegram/VKontakte yn uchel iawn ym maes trafnidiaeth (a lefel is) rhwydweithiau cyfrifiadurol a'u cymwysterau isel mewn materion perthnasol.

Pam y bu mor gymhleth, a sut y gall penseiri Telegram geisio gwrthwynebu? Mae'r ffaith eu bod wedi ceisio gwneud sesiwn sy'n goroesi toriadau cysylltiad TCP, h.y., yr hyn na chafodd ei gyflwyno nawr, byddwn yn cyflawni yn ddiweddarach. Mae'n debyg eu bod hefyd wedi ceisio gwneud cludiant CDU, ond cawsant anawsterau a rhoi'r gorau iddo (dyna pam mae'r ddogfennaeth yn wag - nid oedd dim i frolio yn ei gylch). Ond oherwydd diffyg dealltwriaeth o sut mae rhwydweithiau yn gyffredinol a TCP yn arbennig yn gweithio, lle gallwch chi ddibynnu arno, a lle mae angen i chi ei wneud eich hun (a sut), ac ymgais i gyfuno hyn â cryptograffeg “dau aderyn gyda un garreg”, dyma'r canlyniad.

Sut roedd angen? Yn seiliedig ar y ffaith bod msg_id yn stamp amser angenrheidiol o safbwynt cryptograffig i atal ymosodiadau ailchwarae, camgymeriad yw atodi swyddogaeth dynodwr unigryw iddo. Felly, heb newid y bensaernïaeth gyfredol yn sylfaenol (pan gynhyrchir y ffrwd Diweddariadau, mae hwnnw'n bwnc API lefel uchel ar gyfer rhan arall o'r gyfres hon o swyddi), byddai angen:

  1. Mae'r gweinydd sy'n dal y cysylltiad TCP â'r cleient yn cymryd cyfrifoldeb - os yw wedi darllen o'r soced, a fyddech cystal â chydnabod, prosesu neu ddychwelyd gwall, dim colled. Yna nid yw'r cadarnhad yn fector o ids, ond yn syml “yr olaf a dderbyniwyd seq_no” - dim ond rhif, fel yn TCP (dau rif - eich seq a'r un a gadarnhawyd). Rydyn ni bob amser o fewn y sesiwn, onid ydyn ni?
  2. Mae'r stamp amser i atal ymosodiadau ailchwarae yn dod yn faes ar wahân, a la nonce. Mae'n cael ei wirio, ond nid yw'n effeithio ar unrhyw beth arall. Digon a uint32 - os yw ein halen yn newid o leiaf bob hanner diwrnod, gallwn ddyrannu 16 did i ddarnau trefn isel rhan gyfanrif o'r amser presennol, y gweddill - i ran ffracsiynol o eiliad (fel nawr).
  3. Wedi'i ddileu msg_id o gwbl - o safbwynt gwahaniaethu ceisiadau ar y backends, mae, yn gyntaf, y cleient id, ac yn ail, y sesiwn id, concatenate nhw. Yn unol â hynny, dim ond un peth sy'n ddigonol fel dynodwr cais seq_no.

Nid dyma'r opsiwn mwyaf llwyddiannus ychwaith; gallai hap cyflawn wasanaethu fel dynodwr - mae hyn eisoes yn cael ei wneud yn yr API lefel uchel wrth anfon neges, gyda llaw. Byddai'n well ail-wneud y bensaernïaeth yn llwyr o gymharol i absoliwt, ond pwnc ar gyfer rhan arall yw hwn, nid y swydd hon.

API?

Ta-daam! Felly, ar ôl brwydro trwy lwybr llawn poen a baglau, roeddem o'r diwedd yn gallu anfon unrhyw geisiadau at y gweinydd a derbyn unrhyw atebion iddynt, yn ogystal â derbyn diweddariadau gan y gweinydd (nid mewn ymateb i gais, ond ei hun yn ein hanfon, fel PUSH, os oes unrhyw un, mae'n gliriach felly).

Sylwch, nawr bydd yr unig enghraifft yn Perl yn yr erthygl! (i'r rhai nad ydynt yn gyfarwydd â'r gystrawen, y ddadl bendith gyntaf yw strwythur data'r gwrthrych, yr ail yw ei ddosbarth):

2019.10.24 12:00:51 $1 = {
'cb' => 'TeleUpd::__ANON__',
'out' => bless( {
'filter' => bless( {}, 'Telegram::ChannelMessagesFilterEmpty' ),
'channel' => bless( {
'access_hash' => '-6698103710539760874',
'channel_id' => '1380524958'
}, 'Telegram::InputPeerChannel' ),
'pts' => '158503',
'flags' => 0,
'limit' => 0
}, 'Telegram::Updates::GetChannelDifference' ),
'req_id' => '6751291954012037292'
};
2019.10.24 12:00:51 $1 = {
'in' => bless( {
'req_msg_id' => '6751291954012037292',
'result' => bless( {
'pts' => 158508,
'flags' => 3,
'final' => 1,
'new_messages' => [],
'users' => [],
'chats' => [
bless( {
'title' => 'Хулиномика',
'username' => 'hoolinomics',
'flags' => 8288,
'id' => 1380524958,
'access_hash' => '-6698103710539760874',
'broadcast' => 1,
'version' => 0,
'photo' => bless( {
'photo_small' => bless( {
'volume_id' => 246933270,
'file_reference' => '
'secret' => '1854156056801727328',
'local_id' => 228648,
'dc_id' => 2
}, 'Telegram::FileLocation' ),
'photo_big' => bless( {
'dc_id' => 2,
'local_id' => 228650,
'file_reference' => '
'secret' => '1275570353387113110',
'volume_id' => 246933270
}, 'Telegram::FileLocation' )
}, 'Telegram::ChatPhoto' ),
'date' => 1531221081
}, 'Telegram::Channel' )
],
'timeout' => 300,
'other_updates' => [
bless( {
'pts_count' => 0,
'message' => bless( {
'post' => 1,
'id' => 852,
'flags' => 50368,
'views' => 8013,
'entities' => [
bless( {
'length' => 20,
'offset' => 0
}, 'Telegram::MessageEntityBold' ),
bless( {
'length' => 18,
'offset' => 480,
'url' => 'https://alexeymarkov.livejournal.com/[url_вырезан].html'
}, 'Telegram::MessageEntityTextUrl' )
],
'reply_markup' => bless( {
'rows' => [
bless( {
'buttons' => [
bless( {
'text' => '???? 165',
'data' => 'send_reaction_0'
}, 'Telegram::KeyboardButtonCallback' ),
bless( {
'data' => 'send_reaction_1',
'text' => '???? 9'
}, 'Telegram::KeyboardButtonCallback' )
]
}, 'Telegram::KeyboardButtonRow' )
]
}, 'Telegram::ReplyInlineMarkup' ),
'message' => 'А вот и новая книга! 
// [текст сообщения вырезан чтоб не нарушать правил Хабра о рекламе]
напечатаю.',
'to_id' => bless( {
'channel_id' => 1380524958
}, 'Telegram::PeerChannel' ),
'date' => 1571724559,
'edit_date' => 1571907562
}, 'Telegram::Message' ),
'pts' => 158508
}, 'Telegram::UpdateEditChannelMessage' ),
bless( {
'pts' => 158508,
'message' => bless( {
'edit_date' => 1571907589,
'to_id' => bless( {
'channel_id' => 1380524958
}, 'Telegram::PeerChannel' ),
'date' => 1571807301,
'message' => 'Почему Вы считаете Facebook плохой компанией? Можете прокомментировать? По-моему, это шикарная компания. Без долгов, с хорошей прибылью, а если решат дивы платить, то и еще могут нехило подорожать.
Для меня ответ совершенно очевиден: потому что Facebook делает ужасный по качеству продукт. Да, у него монопольное положение и да, им пользуется огромное количество людей. Но мир не стоит на месте. Когда-то владельцам Нокии было смешно от первого Айфона. Они думали, что лучше Нокии ничего быть не может и она навсегда останется самым удобным, красивым и твёрдым телефоном - и доля рынка это красноречиво демонстрировала. Теперь им не смешно.
Конечно, рептилоиды сопротивляются напору молодых гениев: так Цукербергом был пожран Whatsapp, потом Instagram. Но всё им не пожрать, Паша Дуров не продаётся!
Так будет и с Фейсбуком. Нельзя всё время делать говно. Кто-то когда-то сделает хороший продукт, куда всё и уйдут.
#соцсети #facebook #акции #рептилоиды',
'reply_markup' => bless( {
'rows' => [
bless( {
'buttons' => [
bless( {
'data' => 'send_reaction_0',
'text' => '???? 452'
}, 'Telegram::KeyboardButtonCallback' ),
bless( {
'text' => '???? 21',
'data' => 'send_reaction_1'
}, 'Telegram::KeyboardButtonCallback' )
]
}, 'Telegram::KeyboardButtonRow' )
]
}, 'Telegram::ReplyInlineMarkup' ),
'entities' => [
bless( {
'length' => 199,
'offset' => 0
}, 'Telegram::MessageEntityBold' ),
bless( {
'length' => 8,
'offset' => 919
}, 'Telegram::MessageEntityHashtag' ),
bless( {
'offset' => 928,
'length' => 9
}, 'Telegram::MessageEntityHashtag' ),
bless( {
'length' => 6,
'offset' => 938
}, 'Telegram::MessageEntityHashtag' ),
bless( {
'length' => 11,
'offset' => 945
}, 'Telegram::MessageEntityHashtag' )
],
'views' => 6964,
'flags' => 50368,
'id' => 854,
'post' => 1
}, 'Telegram::Message' ),
'pts_count' => 0
}, 'Telegram::UpdateEditChannelMessage' ),
bless( {
'message' => bless( {
'reply_markup' => bless( {
'rows' => [
bless( {
'buttons' => [
bless( {
'data' => 'send_reaction_0',
'text' => '???? 213'
}, 'Telegram::KeyboardButtonCallback' ),
bless( {
'data' => 'send_reaction_1',
'text' => '???? 8'
}, 'Telegram::KeyboardButtonCallback' )
]
}, 'Telegram::KeyboardButtonRow' )
]
}, 'Telegram::ReplyInlineMarkup' ),
'views' => 2940,
'entities' => [
bless( {
'length' => 609,
'offset' => 348
}, 'Telegram::MessageEntityItalic' )
],
'flags' => 50368,
'post' => 1,
'id' => 857,
'edit_date' => 1571907636,
'date' => 1571902479,
'to_id' => bless( {
'channel_id' => 1380524958
}, 'Telegram::PeerChannel' ),
'message' => 'Пост про 1С вызвал бурную полемику. Человек 10 (видимо, 1с-программистов) единодушно написали:
// [текст сообщения вырезан чтоб не нарушать правил Хабра о рекламе]
Я бы добавил, что блестящая у 1С дистрибуция, а маркетинг... ну, такое.'
}, 'Telegram::Message' ),
'pts_count' => 0,
'pts' => 158508
}, 'Telegram::UpdateEditChannelMessage' ),
bless( {
'pts' => 158508,
'pts_count' => 0,
'message' => bless( {
'message' => 'Здравствуйте, расскажите, пожалуйста, чем вредит экономике 1С?
// [текст сообщения вырезан чтоб не нарушать правил Хабра о рекламе]
#софт #it #экономика',
'edit_date' => 1571907650,
'date' => 1571893707,
'to_id' => bless( {
'channel_id' => 1380524958
}, 'Telegram::PeerChannel' ),
'flags' => 50368,
'post' => 1,
'id' => 856,
'reply_markup' => bless( {
'rows' => [
bless( {
'buttons' => [
bless( {
'data' => 'send_reaction_0',
'text' => '???? 360'
}, 'Telegram::KeyboardButtonCallback' ),
bless( {
'data' => 'send_reaction_1',
'text' => '???? 32'
}, 'Telegram::KeyboardButtonCallback' )
]
}, 'Telegram::KeyboardButtonRow' )
]
}, 'Telegram::ReplyInlineMarkup' ),
'views' => 4416,
'entities' => [
bless( {
'offset' => 0,
'length' => 64
}, 'Telegram::MessageEntityBold' ),
bless( {
'offset' => 1551,
'length' => 5
}, 'Telegram::MessageEntityHashtag' ),
bless( {
'length' => 3,
'offset' => 1557
}, 'Telegram::MessageEntityHashtag' ),
bless( {
'offset' => 1561,
'length' => 10
}, 'Telegram::MessageEntityHashtag' )
]
}, 'Telegram::Message' )
}, 'Telegram::UpdateEditChannelMessage' )
]
}, 'Telegram::Updates::ChannelDifference' )
}, 'MTProto::RpcResult' )
};
2019.10.24 12:00:51 $1 = {
'in' => bless( {
'update' => bless( {
'user_id' => 2507460,
'status' => bless( {
'was_online' => 1571907651
}, 'Telegram::UserStatusOffline' )
}, 'Telegram::UpdateUserStatus' ),
'date' => 1571907650
}, 'Telegram::UpdateShort' )
};
2019.10.24 12:05:46 $1 = {
'in' => bless( {
'chats' => [],
'date' => 1571907946,
'seq' => 0,
'updates' => [
bless( {
'max_id' => 141719,
'channel_id' => 1295963795
}, 'Telegram::UpdateReadChannelInbox' )
],
'users' => []
}, 'Telegram::Updates' )
};
2019.10.24 13:01:23 $1 = {
'in' => bless( {
'server_salt' => '4914425622822907323',
'unique_id' => '5297282355827493819',
'first_msg_id' => '6751307555044380692'
}, 'MTProto::NewSessionCreated' )
};
2019.10.24 13:24:21 $1 = {
'in' => bless( {
'chats' => [
bless( {
'username' => 'freebsd_ru',
'version' => 0,
'flags' => 5440,
'title' => 'freebsd_ru',
'min' => 1,
'photo' => bless( {
'photo_small' => bless( {
'local_id' => 328733,
'volume_id' => 235140688,
'dc_id' => 2,
'file_reference' => '
'secret' => '4426006807282303416'
}, 'Telegram::FileLocation' ),
'photo_big' => bless( {
'dc_id' => 2,
'file_reference' => '
'volume_id' => 235140688,
'local_id' => 328735,
'secret' => '71251192991540083'
}, 'Telegram::FileLocation' )
}, 'Telegram::ChatPhoto' ),
'date' => 1461248502,
'id' => 1038300508,
'democracy' => 1,
'megagroup' => 1
}, 'Telegram::Channel' )
],
'users' => [
bless( {
'last_name' => 'Panov',
'flags' => 1048646,
'min' => 1,
'id' => 82234609,
'status' => bless( {}, 'Telegram::UserStatusRecently' ),
'first_name' => 'Dima'
}, 'Telegram::User' )
],
'seq' => 0,
'date' => 1571912647,
'updates' => [
bless( {
'pts' => 137596,
'message' => bless( {
'flags' => 256,
'message' => 'Создать джейл с именем покороче ??',
'to_id' => bless( {
'channel_id' => 1038300508
}, 'Telegram::PeerChannel' ),
'id' => 119634,
'date' => 1571912647,
'from_id' => 82234609
}, 'Telegram::Message' ),
'pts_count' => 1
}, 'Telegram::UpdateNewChannelMessage' )
]
}, 'Telegram::Updates' )
};

Ie, ddim yn sbwyliwr pwrpasol - os nad ydych chi wedi ei ddarllen eto, ewch ymlaen i wneud!

O, wai~~... sut olwg sydd ar hwn? Rhywbeth cyfarwydd iawn... efallai mai dyma strwythur data API Gwe nodweddiadol yn JSON, ac eithrio bod dosbarthiadau hefyd ynghlwm wrth wrthrychau?..

Felly dyma sut mae'n troi allan ... Beth mae'n ei olygu, gymrodyr?.. Cymaint o ymdrech - ac rydym yn stopio i orffwys lle mae'r rhaglenwyr We newydd ddechrau?.. Oni fyddai JSON yn unig dros HTTPS yn symlach?! Beth gawson ni yn gyfnewid? Oedd yr ymdrech yn werth chweil?

Gadewch i ni werthuso'r hyn a roddodd TL+MTProto inni a pha ddewisiadau eraill sy'n bosibl. Wel, mae HTTP, sy'n canolbwyntio ar y model ymateb i gais, yn ffit wael, ond o leiaf yn rhywbeth ar ben TLS?

Cyfresoli Compact. Wrth weld y strwythur data hwn, yn debyg i JSON, cofiaf fod fersiynau deuaidd ohono. Gadewch i ni nodi nad yw MsgPack yn ddigon estynadwy, ond mae yna, er enghraifft, CBOR - gyda llaw, safon a ddisgrifir yn RFC 7049. Mae'n nodedig am y ffaith ei fod yn diffinio tagiau, fel mecanwaith ehangu, ac ymhlith safoni eisoes ar gael:

  • 25 + 256 - disodli llinellau ailadroddus gyda chyfeiriad at rif y llinell, dull cywasgu mor rhad
  • 26 - gwrthrych Perl cyfresol gydag enw dosbarth a dadleuon lluniwr
  • 27 - gwrthrych cyfresol sy'n annibynnol ar iaith gydag enw teip a dadleuon lluniwr

Wel, ceisiais gyfresoli'r un data yn TL ac yn CBOR gyda phacio llinynnau a gwrthrychau wedi'u galluogi. Dechreuodd y canlyniad amrywio o blaid CBOR rhywle o megabeit:

cborlen=1039673 tl_len=1095092

Felly, casgliad: Mae yna fformatau sylweddol symlach nad ydynt yn destun y broblem o fethiant cydamseru neu ddynodwr anhysbys, gydag effeithlonrwydd tebyg.

Sefydlu cysylltiad cyflym. Mae hyn yn golygu sero RTT ar ôl ailgysylltu (pan fydd yr allwedd eisoes wedi'i chynhyrchu unwaith) - sy'n berthnasol o'r neges MTProto gyntaf, ond gyda rhai amheuon - tarwch yr un halen, nid yw'r sesiwn wedi pydru, ac ati. Beth mae TLS yn ei gynnig i ni yn lle hynny? Dyfyniad ar y pwnc:

Wrth ddefnyddio PFS yn TLS, tocynnau sesiwn TLS (RFC 5077) ailddechrau sesiwn wedi'i hamgryptio heb ail-negodi allweddi a heb storio gwybodaeth allweddol ar y gweinydd. Wrth agor y cysylltiad cyntaf a chreu allweddi, mae'r gweinydd yn amgryptio'r cyflwr cysylltiad ac yn ei drosglwyddo i'r cleient (ar ffurf tocyn sesiwn). Yn unol â hynny, pan fydd y cysylltiad yn ailddechrau, mae'r cleient yn anfon tocyn sesiwn, gan gynnwys allwedd y sesiwn, yn ôl i'r gweinydd. Mae'r tocyn ei hun wedi'i amgryptio ag allwedd dros dro (allwedd tocyn sesiwn), sy'n cael ei storio ar y gweinydd a rhaid ei ddosbarthu ymhlith yr holl weinyddion blaen sy'n prosesu SSL mewn datrysiadau clystyrog.[10]. Felly, gall cyflwyno tocyn sesiwn dorri PFS os yw allweddi gweinydd dros dro yn cael eu peryglu, er enghraifft, pan fyddant yn cael eu storio am amser hir (OpenSSL, nginx, Apache yn eu storio yn ddiofyn am gyfnod cyfan y rhaglen; mae gwefannau poblogaidd yn defnyddio yr allwedd am sawl awr, hyd at ddyddiau).

Yma nid yw'r RTT yn sero, mae angen i chi gyfnewid o leiaf ClientHello a ServerHello, ac ar ôl hynny gall y cleient anfon data ynghyd â Gorffen. Ond yma dylem gofio nad oes gennym y We, gyda'i griw o gysylltiadau newydd eu hagor, ond negesydd, y mae ei gysylltiad yn aml yn un a mwy neu lai o geisiadau hirhoedlog, cymharol fyr i dudalennau Gwe - mae popeth yn amlblecs yn fewnol. Hynny yw, mae'n eithaf derbyniol pe na baem yn dod ar draws adran isffordd wael iawn.

Wedi anghofio rhywbeth arall? Ysgrifennwch yn y sylwadau.

I'w barhau!

Yn ail ran y gyfres hon o swyddi byddwn yn ystyried nid technegol, ond materion trefniadol - ymagweddau, ideoleg, rhyngwyneb, agwedd tuag at ddefnyddwyr, ac ati. Yn seiliedig, fodd bynnag, ar y wybodaeth dechnegol a gyflwynwyd yma.

Bydd y drydedd ran yn parhau i ddadansoddi'r gydran dechnegol / profiad datblygu. Byddwch yn dysgu, yn arbennig:

  • parhad y pandemonium gyda'r amrywiaeth o fathau TL
  • pethau anhysbys am sianeli ac uwch-grwpiau
  • pam mae deialogau yn waeth na rhestr ddyletswyddau
  • am gyfeiriad neges absoliwt yn erbyn cymharol
  • beth yw'r gwahaniaeth rhwng llun a delwedd
  • sut mae emoji yn ymyrryd â thestun italig

a baglau eraill! Aros diwnio!

Ffynhonnell: hab.com

Ychwanegu sylw