38-წუთიანი სამუშაო სესია იმაზე, თუ როგორ მიეწოდოს მონაცემები იმ წამსვე, როცა ისინი იცვლება — WebSocket-ის handshake და ფრეიმები, კავშირის სასიცოცხლო ციკლი, რომელსაც თავად უნდა მართავდეთ (heartbeat, ხელახლა დაკავშირება), pub/sub და presence პატერნები, რომლებზეც რეალური დროის აპლიკაციები დგას, როგორ გავმასშტაბდეთ ბევრ სერვერზე ბექფლეინით და როდის არის უფრო მსუბუქი ტრანსპორტი (SSE, long-polling, WebRTC) სწორი არჩევანი — იმ რეალურ ბიბლიოთეკებთან და მართულ სერვისებთან ერთად, რომლებსაც მართლა გამოიყენებთ.
ჩვეულებრივი HTTP მოთხოვნა/პასუხია: კლიენტი ეკითხება, სერვერი პასუხობს, კავშირი იხურება. ეს იდეალურია გვერდის ჩასატვირთად — და არასწორია ყველაფრისთვის, რაც თავისით იცვლება. ჩატი, ცოცხალი დაშბორდები, მრავალმოთამაშიანი კურსორები, შეკვეთის თვალყურის დევნება, შეტყობინებები: ჯერ სერვერმა იცის, ამიტომ სერვერმა უნდა ილაპარაკოს პირველმა.
პოლინგის საშუალო შეყოვნება ინტერვალის ნახევარია და პასუხების უმეტესობა ცარიელია. push კი ერთხელ მოდის — ზუსტად მაშინ, როცა გასაგზავნი რამ არის.
304/ცარიელია, მაგრამ მაინც ჯდება შემოვლა და ბაზაზე მიმართვა.თითქოს ყოველ წუთს რეკავთ სამზარეულოში და კითხულობთ, ვახშამი მზად არის თუ არა — იმის ნაცვლად, რომ მზარეულმა თავად დაგირეკოთ, როგორც კი მზად იქნება.
WebSocket-ს ცარიელ ადგილას ვერ გახსნით. ის იწყება ჩვეულებრივი HTTP GET-ით, რომელსაც Upgrade ჰედერი მოაქვს; თუ სერვერი დათანხმდა, იგივე TCP კავშირი წყვეტს HTTP-ზე საუბარს და WebSocket-ის პროტოკოლზე გადადის — სრულ დუპლექსში, სადაც ორივე მხარეს ნებისმიერ დროს შეუძლია გაგზავნა.
ws://-ს იყენებს, ან TLS-ზე — wss://-ს; პროდაქშენში ყოველთვის ამჯობინეთ wss (დაშიფრულია და ბევრად უფრო სავარაუდოა, რომ პროქსებს გაუძლოს).text, binary, ping, pong ან close.onmessage-ს იღებთ.ფრეიმი ძირითადად დატვირთვაა: ორიოდე ბაიტი ჰედერი და შემდეგ თქვენი ბაიტები. შეტყობინებაზე HTTP-ის ზედნადები არ არის.
ხანგრძლივი კავშირი იმდენადვე ტვირთია, რამდენადაც ფუნქციონალი: ლეპტოპები იძინებენ, Wi-Fi კრთება, ტელეფონები ქსელს იცვლიან და პროქსები ჩუმად წყვეტენ უქმ კავშირებს. რეალური დროის კოდი ძირითადად სწორედ ამის გადატანაზეა — მკვდარი სოკეტის სწრაფად შემჩნევასა და ქსელში სუფთად დაბრუნებაზე.
open, message, close, error. ის ორი კი, რომლებზეც აპლიკაციის საიმედოობის შეგრძნება დგას, თქვენ თვითონ უნდა დაამატოთ: heartbeat (მკვდარი არხის შესამჩნევად) და ხელახლა დაკავშირება backoff-ით (რომ სერვერს ჯოგად არ დაერიოთ).ბედნიერი გზა ერთი ნახტომია; ნამდვილი სამუშაო კი ციკლია — დახურული → ხელახალი კავშირი → (backoff-ის პაუზის შემდეგ) → ვუკავშირდები.
// ping on a timer; expect a pong back setInterval(() => ws.send('{"t":"ping"}'), 15_000) // no pong within a few seconds? // the socket is half-open — treat it as dead // and trigger a reconnect.
let wait = 1_000 ws.onclose = () => { setTimeout(connect, wait) // exponential backoff, capped + jittered wait = Math.min(wait * 2, 30_000) }
რეალური დროის აპლიკაციები ძალიან იშვიათად არის ერთი-ერთთან. მთავარი ფორმა არის publish/subscribe: კლიენტები ერთვებიან დასახელებულ არხზე და როცა რამე ხდება, სერვერი ამას ყველა გამომწერს ავრცელებს — ისე, რომ გამომცემმა არც კი იცის, ვინ უსმენს.
ერთხელ გამოაქვეყნეთ არხში; სერვერი მას ყველა მიმდინარე გამომწერს ავრცელებს. გამომცემი მიმღებებს არასდროს ასახელებს.
დააჯგუფეთ სოკეტები სახელის ქვეშ (room:42, user:7), რომ გავრცელება ზუსტად სწორ კლიენტებამდე მივიდეს — და არა ყველასთან, ვინც დაკავშირებულია.
აღრიცხეთ არხის წევრობა და გამოსცემით შემოსვლა/გასვლა. ამაზე დგას „3 ადამიანი ონლაინ“, ავატარები და ცოცხალი „ბეჭდავს…“ ინდიკატორები.
მომხმარებელი, რომელიც ვერ ეწევა, არჩევანის წინაშე გაყენებთ: დააბუფეროთ (მეხსიერების რისკი), ჩააგდოთ (დანაკარგი) ან გათიშოთ. გადაწყვიტეთ გააზრებულად, თითოეული არხისთვის.
// server (Socket.IO rooms) socket.join('room:42') io.to('room:42').emit('message', payload) // only sockets that joined room:42 receive it
ერთ პროცესს ათიათასობით სოკეტის დაჭერა შეუძლია, მაგრამ ადრე თუ გვიან ერთზე მეტს გაუშვებთ. სწორედ მაშინ ტყდება გულუბრყვილო გავრცელება: ერთი ჩატის ორი მომხმარებელი შეიძლება სხვადასხვა სერვერზე იყოს დაკავშირებული და ერთზე გამოქვეყნებული შეტყობინება მეორემდე ვერასდროს მივა.
სერვერ A-ზე მისული შეტყობინება Redis-ში ქვეყნდება, ის კი მას სერვერ B-ს აწვდის — ასე რომ B-ს კლიენტებიც ხედავენ. ყოველი ნოუდი აქვეყნებს და ერთდროულად გამომწერიცაა.
ამის უმეტესობა — მიბმა, ბექფლეინი, presence, კავშირების ლიმიტები — ზუსტად ის არის, რასაც რეალური დროის მართული სერვისი თქვენს ნაცვლად აგვარებს. ააშენეთ თავად, როცა კონტროლი გჭირდებათ; იყიდეთ, როცა ურჩევნიათ, რომ პროდუქტი გაუშვათ.
სრულ დუპლექსიანი სოკეტი ძლიერია, მაგრამ მისი მართვა მძიმეა. სამი სხვა ტრანსპორტი რეალური დროის ბევრ საჭიროებას გაცილებით ნაკლები საოპერაციო წონით ფარავს — და ერთი მათგანი (SSE) სწორი ნაგულისხმევია ყველაზე გავრცელებული შემთხვევისთვის: სერვერი→კლიენტი ნაკადებისთვის.
const es = new EventSource('/api/stream') es.onmessage = (e) => render(e.data) // auto-reconnect is built in. text only.
გამოიყენეთ, როცა: შეტყობინებები, ცოცხალი ანგარიში, პროგრესი, ლოგებისა და AI ტოკენების ნაკადები — ყველაფერი, რაც კლიენტს მხოლოდ მისაღებად სჭირდება.
კლიენტი აგზავნის მოთხოვნას, რომელსაც სერვერი ღიად იჭერს, სანამ მონაცემი არ გაჩნდება (ან ტაიმაუტი არ დადგება), შემდეგ კი მაშინვე ხელახლა ითხოვს. ეს push-ს მხოლოდ ჩვეულებრივი HTTP-ით ბაძავს.
გამოიყენეთ, როცა: მხარდაჭერის მინიმალური ზღვარი გჭირდებათ; Socket.IO-ს მსგავსი ბიბლიოთეკები მას ავტომატურად იყენებენ, როცა WebSockets დაბლოკილია.
პირდაპირი ბრაუზერიდან ბრაუზერამდე არხები აუდიოსთვის, ვიდეოსთვის და დაბალი შეყოვნების მონაცემებისთვის — სერვერი ძირითადად მხოლოდ ეხმარება მხარეებს, რომ ერთმანეთი იპოვონ (სიგნალინგი).
გამოიყენეთ, როცა: ვიდეო- და ხმოვანი ზარები, ეკრანის გაზიარება ან P2P თამაშები, სადაც ყოველი მილიწამი ითვლება.
დაიწყეთ საჭიროებიდან: „ცოცხალი“ ფუნქციების უმეტესობა ცალმხრივია და SSE საკმარისია; WebSocket-ს მაშინ მიმართეთ, როცა კლიენტმაც უნდა ილაპარაკოს.
RFC 6455-ს ხელით იშვიათად წერთ. ნამდვილი არჩევანი არის აგება თუ ყიდვა: ბიბლიოთეკა, რომელსაც თავად უშვებთ, თუ მართული სერვისი, რომელიც რთულ ნაწილებს (მასშტაბირება, presence, გლობალური მიწოდება) ითავსებს. აი წამყვანი ვარიანტები, თითოეული ერთი პატიოსანი დადებითი და უარყოფითი მხარით.
პაწაწინა, სტანდარტისადმი სუფთა WebSocket-ის იმპლემენტაცია Node-ისთვის. იღებთ ნედლ ფრეიმებს და მეტს არაფერს.
უფრო მაღალი დონის შრე ოთახებით, ავტომატური ხელახლა დაკავშირებით, long-poll სარეზერვო გზითა და Redis ადაპტერით მასშტაბირებისთვის.
დამოუკიდებელი, ენისგან დამოუკიდებელი pub/sub სერვერები (Soketi Pusher-ის პროტოკოლთან თავსებადია), რომლებსაც აპლიკაციის გვერდით უშვებთ.
ჰოსტირებული არხები presence-ით, შეტყობინებების ისტორიითა და მიწოდების გარანტიებით გლობალურ ქსელზე.
ერთ-ერთი პირველი ჰოსტირებული pub/sub სერვისი — სწრაფად ეწყობა გავრცელებისა და presence-ისთვის.
ღიაკოდიანი სერვისი, რომელიც Postgres-ის სტრიქონების ცვლილებებს ნაკადად გადმოსცემს, პლუს გავრცელებისა და presence-ის არხები.
როგორ ავირჩიოთ: ws — როცა სუფთა WebSockets გინდათ და მასშტაბირებას თავად იტვირთავთ; Socket.IO — სრული ნაკრებისთვის ერთ აპლიკაციაში; Centrifugo/Soketi — რომ მასშტაბირებადი მაგისტრალი თვითონ დაჰოსტოთ; Ably/Pusher/Supabase — როცა გირჩევნიათ, გადაიხადოთ და მასშტაბირება, presence და გლობალური მიწოდება სხვის საზრუნავად აქციოთ.
ხუთი სწრაფი კითხვა რეალური დროის ტრანსპორტებზე, WebSocket-ის handshake-ზე, სასიცოცხლო ციკლსა და მასშტაბირებაზე — მყისიერი პასუხი, ავტორიზაციის გარეშე.
ნავიგაცია ← → ღილაკებით ან სქროლით · უკან ბიბლიოთეკაში