{"id":345855,"date":"2023-02-25T03:00:46","date_gmt":"2023-02-25T03:00:46","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=345855"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=345855","title":{"rendered":"<span>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u00abGoogle\u00a0Sheets\u00bb \u0447\u0435\u0440\u0435\u0437 Websockets \u043d\u0430 Node.js<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/upload_files\/0b9\/c39\/3bc\/0b9c393bc0a9a2c3c9a2cc984ad70689.jpg\" width=\"1140\" height=\"467\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/0b9\/c39\/3bc\/0b9c393bc0a9a2c3c9a2cc984ad70689.jpg\" data-blurred=\"true\"\/><figcaption><\/figcaption><\/figure>\n<h3>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/h3>\n<p>\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442! \u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0413\u0435\u0440\u043c\u0430\u043d \u041f\u0430\u043d\u043e\u0432 \u0438 \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440 &#8212; \u0430\u043d\u0430\u043b\u043e\u0433 Google\u00a0Sheets (\u0432 \u0443\u043f\u0440\u043e\u0449\u0435\u043d\u043d\u043e\u043c \u0432\u0438\u0434\u0435), \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0432\u0435\u0431\u0441\u043e\u043a\u0435\u0442\u043e\u0432, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0430\u043c\u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430\u0445. <\/p>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0446\u0435\u043b\u044c &#8212; \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u043b\u0435\u043d\u0438\u0435, \u043a\u043e\u0434 \u0431\u0443\u0434\u0435\u0442 \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u00ab\u0447\u0438\u0441\u0442\u044b\u043c\u00bb, \u043d\u043e \u0434\u043b\u044f \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u044d\u0442\u043e\u0433\u043e \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Node.js, \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043f\u0430\u043a\u0435\u0442 <a href=\"https:\/\/www.npmjs.com\/package\/ws\" rel=\"noopener noreferrer nofollow\">ws<\/a>, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 API \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0432\u0435\u0431\u0441\u043e\u043a\u0435\u0442\u0430\u043c\u0438 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435.<\/p>\n<h2>\u0417\u0430\u0434\u0430\u0447\u0430<\/h2>\n<p>\u0421\u043e\u0437\u0434\u0430\u0442\u044c \u0442\u0430\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440 \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c\u0438 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f\u043c\u0438:<\/p>\n<p><em>\u0424\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f<\/em><\/p>\n<ul>\n<li>\n<p>\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u044f\u0447\u0435\u0435\u043a \u0442\u0430\u0431\u043b\u0438\u0446\u044b<\/p>\n<\/li>\n<li>\n<p>\u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b<\/p>\n<\/li>\n<li>\n<p>\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438 \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438<\/p>\n<\/li>\n<\/ul>\n<p><em>\u041d\u0430\u0433\u0440\u0443\u0437\u043e\u0447\u043d\u044b\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f<\/em><\/p>\n<ul>\n<li>\n<p>\u0422\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439 \u043f\u043e \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0435 \u043d\u0435\u0442<\/p>\n<\/li>\n<\/ul>\n<h2>\u0422\u0435\u043e\u0440\u0438\u044f. \u041f\u0440\u043e\u0442\u043e\u043a\u043e\u043b Websocket<\/h2>\n<p>\u041f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u00a0<code>WebSocket<\/code>(\u00ab\u0432\u0435\u0431-\u0441\u043e\u043a\u0435\u0442\u00bb) \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e\u0433\u043e \u0434\u0432\u0443\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0435\u0433\u043e \u043e\u0431\u043c\u0435\u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043c\u0435\u0436\u0434\u0443 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c. \u0421\u0435\u0440\u0432\u0435\u0440 \u0432 \u043b\u044e\u0431\u043e\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u0440\u0438\u0441\u043b\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0443, \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e, \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u043b \u043b\u0438 \u0435\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442 \u0438\u043b\u0438 \u043d\u0435\u0442. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0443 \u043d\u0443\u0436\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c <code>handshake<\/code> (\u00ab\u0440\u0443\u043a\u043e\u043f\u043e\u0436\u0430\u0442\u0438\u044f\u00bb)<\/p>\n<p>\u0411\u0440\u0430\u0443\u0437\u0435\u0440, \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0445 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043b\u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u043e\u0431\u043c\u0435\u043d \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043f\u043e Websocket, \u0438 \u0435\u0441\u043b\u0438 \u0434\u0430, \u00ab\u043e\u0431\u0449\u0435\u043d\u0438\u0435\u00bb \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0443\u0436\u0435 \u043f\u043e WebSocket. <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/581\/0d9\/cda\/5810d9cda921b9e6891d61e2fdd0074a.png\" width=\"1400\" height=\"1050\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/581\/0d9\/cda\/5810d9cda921b9e6891d61e2fdd0074a.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041d\u0430 \u043f\u0440\u0438\u043a\u043b\u0430\u0434\u043d\u043e\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442 \u0432 \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0435 UTF-8, \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f JSON \u0444\u043e\u0440\u043c\u0430\u0442. \u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c\u044b\u0435 \u043f\u043e WebSocket, \u043c\u043e\u0436\u043d\u043e \u0432\u043e \u0432\u043a\u043b\u0430\u0434\u043a\u0435 Network -> WS \u0432 \u0434\u0435\u0432\u0442\u0443\u043b\u0437\u0430\u0445 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430.<\/p>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u0435\u0442 TCP. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0434\u0430\u043d\u043d\u044b\u0435 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0438\u0440\u0443\u044e\u0442\u0441\u044f, \u043f\u043e Websocket \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0434\u0430\u0436\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043c\u0430. \u041a\u0430\u0436\u0434\u043e\u0435 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0437\u0431\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0444\u0440\u0435\u0439\u043c\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e \u0441\u0432\u043e\u0435\u0439 \u0441\u0443\u0442\u0438 \u043f\u043e\u0445\u043e\u0436\u0438 \u043d\u0430 http-\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0424\u0440\u0435\u0439\u043c &#8212; \u044d\u0442\u043e \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a + \u00ab\u043f\u043e\u043b\u0435\u0437\u043d\u0430\u044f \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0430\u00bb. \u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0441\u043b\u0443\u0436\u0435\u0431\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0444\u0440\u0435\u0439\u043c\u0435 \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445. \u041f\u043e\u043b\u0435\u0437\u043d\u0430\u044f \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 &#8212; \u044d\u0442\u043e \u043b\u044e\u0431\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u0435 \u0442\u0435\u043a\u0441\u0442\u0443 http-\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0412\u0438\u0434 \u0444\u0440\u0435\u0439\u043c\u0430:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/200\/f53\/45c\/200f5345cf142b8c3b25a99f8ff47e5f.png\" width=\"713\" height=\"375\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/200\/f53\/45c\/200f5345cf142b8c3b25a99f8ff47e5f.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0412 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u0435\u0441\u0442\u044c API \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0432\u0435\u0431\u0441\u043e\u043a\u0435\u0442\u0430\u043c\u0438, \u0434\u043b\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442 Websocket, \u043f\u0435\u0440\u0435\u0434\u0430\u0432 URL \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430. \u041f\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0438 \u0441 HTTP \u0435\u0441\u0442\u044c \u0434\u0432\u0430 \u0442\u0438\u043f\u0430 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f: \u0441 \u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c (wss) \u0438 \u0431\u0435\u0437 (ws).<\/p>\n<p>\u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043d\u0443\u0436\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043a\u043e\u043b\u0431\u044d\u043a-\u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0443 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430. \u0415\u0441\u0442\u044c 3 \u0442\u0438\u043f\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0434\u043b\u044f \u0441\u0435\u0442\u0435\u0432\u044b\u0445 \u0441\u043e\u0431\u044b\u0442\u0438\u0439: onopen, onerror, onclose \u0438 \u043e\u0434\u0438\u043d \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0434\u043b\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439: onmessage. (\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c <a href=\"https:\/\/websockets.spec.whatwg.org\/#the-websocket-interface\" rel=\"noopener noreferrer nofollow\">\u0442\u0443\u0442<\/a>). <\/p>\n<p>\u0414\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0441\u043e\u043a\u0435\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043c\u0435\u0442\u043e\u0434 send.<\/p>\n<pre><code class=\"javascript\">const ws = new WebSocket('ws:\/\/localhost\/echo');  ws.onopen = event => {     alert('onopen');      ws.send(\"Hello Web Socket!\"); };  ws.onmessage = event => {     alert('onmessage, ' + event.data); };  ws.onclose = event => {     alert('onclose'); };  ws.onerror = event => {     alert('onerror'); };<\/code><\/pre>\n<p>\u041d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u0443\u044e WebSocket \u043a\u043b\u0438\u0435\u043d\u0442-\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <a href=\"https:\/\/github.com\/websockets\/ws\" rel=\"noopener noreferrer nofollow\">ws<\/a> \u0434\u043b\u044f <a href=\"https:\/\/nodejs.org\/\" rel=\"noopener noreferrer nofollow\"><u>Node.js<\/u><\/a>. \u041f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c\u043e\u0435 API \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u0445\u043e\u0436\u0435 \u043d\u0430 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0435.<\/p>\n<p>\u041f\u043e\u043b\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0449\u0438\u0445 \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 WebSocket \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/WebSockets_API#tools\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a><\/p>\n<p>\u0412 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c WebSocket \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u044b\u0439 \u043e\u0431\u043c\u0435\u043d \u0434\u0430\u043d\u043d\u044b\u043c\u0438:<\/p>\n<ul>\n<li>\n<p>\u0418\u0433\u0440\u044b<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u0435\u0442\u0438 \u0438 \u0447\u0430\u0442\u044b<\/p>\n<\/li>\n<li>\n<p>\u0422\u043e\u0440\u0433\u043e\u0432\u044b\u0435 \u043f\u043b\u043e\u0449\u0430\u0434\u043a\u0438<\/p>\n<\/li>\n<li>\n<p>\u0423\u043c\u043d\u044b\u0439 \u0434\u043e\u043c<\/p>\n<\/li>\n<\/ul>\n<h2>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f. \u041d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0430<\/h2>\n<p>\u041f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0443 Node.js. \u0418\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044e \u043f\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0435 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u043d\u0430 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u043c <a href=\"https:\/\/nodejs.org\/\" rel=\"noopener noreferrer nofollow\">\u0441\u0430\u0439\u0442\u0435<\/a><\/p>\n<p>\u041f\u0440\u043e\u0435\u043a\u0442 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u0442\u044c \u0438\u0437 \u0434\u0432\u0443\u0445 \u0444\u0430\u0439\u043b\u043e\u0432:<\/p>\n<ul>\n<li>\n<p>HTML-\u0444\u0430\u0439\u043b \u0441 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u043e\u0439, \u0441\u0442\u0438\u043b\u044f\u043c\u0438 \u0438 \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u043c \u0434\u043b\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0439 \u0447\u0430\u0441\u0442\u0438<\/p>\n<\/li>\n<li>\n<p>JS-\u0444\u0430\u0439\u043b \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u043e\u0439, \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0449\u0435\u0439 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043f\u043e \u0441\u0435\u0442\u0438<\/p>\n<\/li>\n<\/ul>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u043a\u0435\u043b\u0435\u0442 \u043f\u0440\u043e\u0435\u043a\u0442\u0430:<\/p>\n<ol>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u0430\u0442\u0430\u043b\u043e\u0433 \u043f\u043e\u0434 \u043f\u0440\u043e\u0435\u043a\u0442.<\/p>\n<\/li>\n<li>\n<p>\u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u043d\u043e\u0432\u044b\u0439 git-\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0432 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u043c \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435.<\/p>\n<\/li>\n<li>\n<p>\u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u043d\u043e\u0432\u044b\u0439 npm-\u043f\u0430\u043a\u0435\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043a\u043e\u0434 \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0430\u043a\u0435\u0442\u044b. \u0418\u0437 \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0430\u043a\u0435\u0442 <a href=\"https:\/\/www.npmjs.com\/package\/ws\" rel=\"noopener noreferrer nofollow\">ws<\/a>.<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b .gitignore, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u043f\u0438\u0448\u0435\u043c \u043a\u0430\u0442\u0430\u043b\u043e\u0433 &#171;node_modules&#187;, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0442\u044f\u043d\u0443\u0442\u044c \u043a\u0430\u0442\u0430\u043b\u043e\u0433 \u0441 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u043c\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438 \u0432 git \u043d\u0435 \u0441\u0442\u043e\u0438\u0442.<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"bash\"># \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u0430\u0442\u0430\u043b\u043e\u0433 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u0432 \u043d\u0435\u0433\u043e mkdir websocket-example &amp;&amp; cd websocket-example  # \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c git-\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 git init  # \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c npm-\u043f\u0430\u043a\u0435\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043a\u043e\u0434 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 npm init -y  # \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 WebSocket \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 npm install ws  # \u0423\u043a\u0430\u0436\u0435\u043c git \u043d\u0435 \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u043a\u0430\u0442\u0430\u043b\u043e\u0433 \u0441 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u043c\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438 touch .gitignore &amp;&amp; echo \"node_modules\" >> .gitignore<\/code><\/pre>\n<p>\u0411\u0430\u0437\u043e\u0432\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043e, \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0430\u0442\u044c \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>\u041e\u0440\u0433\u0430\u043d\u0438\u0437\u0443\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0430:<\/p>\n<p>node_modules<br \/>public\/index.html<br \/>src\/server.js<br \/>.gitignore<br \/>package\u2011lock.json<br \/>package.json<\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0437\u0430\u0434\u0430\u0447\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430:<\/p>\n<ul>\n<li>\n<p>\u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439.<\/p>\n<\/li>\n<li>\n<p>\u041e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043f\u0440\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u0440\u0430\u0437\u043e\u0441\u043b\u0430\u0442\u044c \u0435\u0433\u043e \u0432\u0441\u0435\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044b\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438.<\/p>\n<h3>server.js<\/h3>\n<ol>\n<li>\n<p>\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/p>\n<ul>\n<li>\n<p>\u041e\u0431\u044a\u044f\u0432\u0438\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438<\/p>\n<pre><code class=\"javascript\">const ws = require(\"ws\"); const fs = require(\"fs\"); const http = require(\"http\");<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043c \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c http-\u0441\u0435\u0440\u0432\u0435\u0440<\/p>\n<pre><code class=\"javascript\">const index = fs.readFileSync(\"public\/index.html\", \"utf8\");<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c http-\u0441\u0435\u0440\u0432\u0435\u0440<\/p>\n<ol>\n<li>\n<p>\u0417\u0430\u0434\u0430\u0435\u043c \u0430\u0434\u0440\u0435\u0441 \u0445\u043e\u0441\u0442\u0430 \u0438 \u043f\u043e\u0440\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0441\u043b\u0443\u0448\u0438\u0432\u0430\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440.<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0430\u0435\u043c \u043d\u043e\u0432\u044b\u0439 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u0432 \u043a\u043e\u043b\u0431\u044d\u043a\u0435 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c, \u0447\u0442\u043e \u043d\u0430 \u0432\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0441\u0435\u0440\u0432\u0435\u0440 \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0439 index.html \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442 \u0441 200 \u043a\u043e\u0434\u043e\u043c \u043e\u0442\u0432\u0435\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0441\u0435\u0440\u0432\u0435\u0440, \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u043d\u0430\u0447\u0430\u043b \u043f\u0440\u043e\u0441\u043b\u0443\u0448\u0438\u0432\u0430\u0442\u044c \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u0439 \u0445\u043e\u0441\u0442 \u0438 \u043f\u043e\u0440\u0442. \u0412\u044b\u0432\u0435\u0434\u0435\u043c \u0432 \u043b\u043e\u0433\u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e\u0431 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u043c \u043d\u0430\u0447\u0430\u043b\u0435 \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u0435\u0440\u0432\u0435\u0440\u0430.<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"javascript\">const HOST = \"127.0.0.1\"; const PORT = 8000;  const server = http.createServer((req, res) => {     res.writeHead(200);     res.end(index); });  server.listen(PORT, HOST, () => {     console.log(`Server running at http:\/\/${HOST}:${PORT}\/`); });<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c Websocket-\u0441\u0435\u0440\u0432\u0435\u0440, \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u043f\u043e\u0432\u0435\u0440\u0445 http-\u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/p>\n<pre><code class=\"javascript\">const wss = new ws.WebSocketServer({ server });<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043c\u0430\u0441\u0441\u0438\u0432 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439<\/p>\n<pre><code class=\"javascript\">const messages = [];<\/code><\/pre>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>\u041b\u043e\u0433\u0438\u043a\u0430 \u0441\u0435\u0442\u0435\u0432\u043e\u0433\u043e \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f<\/p>\n<ul>\n<li>\n<p>\u041d\u043e\u0432\u044b\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f<\/p>\n<pre><code class=\"javascript\">\/*   \u041a\u043b\u0430\u0441\u0441 WebSocketServer \u0438\u043c\u0435\u0435\u0442 \u043c\u0435\u0442\u043e\u0434 on, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0439 \u043f\u043e\u0433\u0440\u0443\u0437\u0438\u0442\u044c\u0441\u044f   \u0432\u043d\u0443\u0442\u0440\u044c \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0433\u043e \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0438 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043a\u0430\u043a\u0438\u0445-\u043b\u0438\u0431\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u0439.    \u041c\u0435\u0442\u043e\u0434 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043f\u0435\u0440\u0432\u044b\u043c \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u043c \u0441\u043e\u0431\u044b\u0442\u0438\u0435, \u0430 \u0432\u0442\u043e\u0440\u044b\u043c \u043a\u043e\u043b\u0431\u044d\u043a \u043d\u0430 \u044d\u0442\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u0435    \u0422\u0438\u043f\u044b \u0441\u043e\u0431\u044b\u0442\u0438\u0439: \"connection\" | \"message\" | \"error\" | \"close\"    \u0412\u0442\u043e\u0440\u044b\u043c \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u043a\u043e\u043b\u0431\u044d\u043a, \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u0443\u0434\u0443\u0442   \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0438 \u0437\u0430\u043f\u0440\u043e\u0441, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0439 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043b\u0443\u0436\u0435\u0431\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e *\/  wss.on(\"connection\", (websocketConnection, req) => {     \/\/ \u0437\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0435\u0442 \u043b\u043e\u0433\u0438\u043a\u0430 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f });<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f<\/p>\n<p>\u041f\u0440\u0438 \u043d\u043e\u0432\u043e\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u0431\u0443\u0434\u0435\u043c \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u044c \u0432 \u043b\u043e\u0433\u0438 ip-\u0430\u0434\u0440\u0435\u0441 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0432\u0448\u0435\u0433\u043e\u0441\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0438 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0442\u044c \u0440\u0430\u0441\u0441\u044b\u043b\u043a\u0443 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439.<\/p>\n<pre><code class=\"javascript\">wss.on(\"connection\", (websocketConnection, req) => {     const ip = req.socket.remoteAddress;      console.log(`[open] Connected ${ip}`);  broadcastMessages(messages, websocketConnection); });<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f<\/p>\n<p>\u041f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0435\u043c \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u044c \u0435\u0433\u043e \u0432 \u043b\u043e\u0433\u0438, \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0432 \u043c\u0430\u0441\u0441\u0438\u0432 \u0443\u0436\u0435 \u0438\u043c\u0435\u044e\u0449\u0438\u0445\u0441\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0438 \u0440\u0430\u0441\u0441\u044b\u043b\u0430\u0442\u044c \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c.<\/p>\n<pre><code class=\"javascript\">wss.on(\"connection\", (websocketConnection, req) => {     const ip = req.socket.remoteAddress;     console.log(`[open] Connected ${ip}`);  broadcastMessages(messages, websocketConnection);      websocketConnection.on(\"message\", (message) => {         console.log(\"[message] Received: \" + message);  messages.push(message);          broadcastMessage(message, websocketConnection);     }); });<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430<\/p>\n<p>\u041f\u0440\u0438 \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0431\u0443\u0434\u0435\u043c \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u044c \u0432 \u043b\u043e\u0433\u0438 \u0435\u0433\u043e ip-\u0430\u0434\u0440\u0435\u0441.<\/p>\n<pre><code class=\"javascript\">wss.on(\"connection\", (websocketConnection, req) => {     const ip = req.socket.remoteAddress;     console.log(`[open] Connected ${ip}`);  broadcastMessages(messages, websocketConnection);      websocketConnection.on(\"message\", (message) => {         console.log(\"[message] Received: \" + message);  messages.push(message);          broadcastMessage(message, websocketConnection);     });      websocketConnection.on(\"close\", () => {         console.log(`[close] Disconnected ${ip}`);     }); });<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u0412\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438<\/p>\n<ul>\n<li>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0440\u0430\u0441\u0441\u044b\u043b\u043a\u0438 \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439<\/p>\n<pre><code class=\"javascript\">function broadcastMessages(messages, client) {     messages.forEach((message) => {         if (client.readyState === ws.OPEN) {             client.send(message, { binary: false });         }     }); }<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0440\u0430\u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f<\/p>\n<pre><code class=\"javascript\">\/*   \u0414\u043e\u0441\u0442\u0443\u043f \u043a \u0441\u043f\u0438\u0441\u043a\u0443 \u0442\u0435\u043a\u0443\u0449\u0438\u0445 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f   \u0447\u0435\u0440\u0435\u0437 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e clients \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430.    \u041d\u0435 \u0437\u0430\u0431\u0443\u0434\u0435\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c, \u0447\u0442\u043e \u043a\u043b\u0438\u0435\u043d\u0442 \u0433\u043e\u0442\u043e\u0432 \u043a \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044e \u0438 \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u0430,   \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0432\u0448\u0435\u0433\u043e \u044d\u0442\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u0435 (\u0443 \u043d\u0435\u0433\u043e \u043e\u043d\u043e \u0443\u0436\u0435 \u0435\u0441\u0442\u044c). *\/  function broadcastMessage(message, websocketConnection) {     wss.clients.forEach((client) => {         if (client.readyState === ws.OPEN &amp;&amp; client !== websocketConnection) {             client.send(message, { binary: false });         }     }); }<\/code><\/pre>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f.<\/p>\n<h3>index.html<\/h3>\n<p>\u0412 \u043a\u043b\u0438\u0435\u043d\u0442\u043a\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0431\u0443\u0434\u0435\u0442 \u0442\u0430\u0431\u043b\u0438\u0446\u0430, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u043c\u0438. \u041f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043d\u0430 \u043b\u044e\u0431\u0443\u044e \u044f\u0447\u0435\u0439\u043a\u0443, \u043e\u043d\u0430 \u043f\u043e\u0434\u0441\u0432\u0435\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0438 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0434\u043b\u044f \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/049\/b2b\/b03\/049b2bb036780f3c552c2609fc868b61.png\" width=\"auto\" height=\"auto\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/049\/b2b\/b03\/049b2bb036780f3c552c2609fc868b61.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0412 public\/index.html \u0431\u0443\u0434\u0435\u0442 \u0432\u0441\u0435: \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0430, \u0441\u0442\u0438\u043b\u0438, \u0434\u0438\u043d\u0430\u043c\u0438\u043a\u0430. \u042d\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0438\u043c\u0435\u043d\u043d\u043e \u0432 index.html, \u0442\u0430\u043a \u043a\u0430\u043a \u0441\u0435\u0440\u0432\u0435\u0440 \u043e\u0442\u0434\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0433\u043e.<\/p>\n<ul>\n<li>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0441\u0442\u0440\u0443\u0442\u0443\u0440\u0443 html \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430<\/p>\n<pre><code class=\"xml\">&lt;!DOCTYPE html> &lt;html lang=\"en\">     &lt;head>         &lt;style>          &lt;! -- \u0437\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0443\u0442 \u0441\u0442\u0438\u043b\u0438 -->         &lt;\/style>     &lt;\/head>     &lt;body>   &lt;! -- \u0442\u0430\u0431\u043b\u0438\u0446\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c\u0441\u044f -->         &lt;table id=\"table\">&lt;\/table>     &lt;\/body>     &lt;script>     &lt;! -- \u0437\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0435\u0442 \u043b\u043e\u0433\u0438\u043a\u0430 -->     &lt;\/script> &lt;\/html> <\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u0421\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0443\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0443<\/p>\n<pre><code class=\"javascript\">const COLUMNS = [\"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"I\", \"K\", \"L\", \"M\", \"O\"]; const ROWS_COUNT = 30;  const table = document.querySelector(\"#table\");<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u044f\u0447\u0435\u0435\u043a \u0442\u0430\u0431\u043b\u0438\u0446\u044b<\/p>\n<pre><code class=\"javascript\">const cells = {};<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u0418\u043d\u0438\u0446\u0438\u0438\u0440\u0443\u0435\u043c Websocket-\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c<\/p>\n<pre><code class=\"javascript\">const HOST = \"127.0.0.1\"; const PORT = \"8000\";  const API_URL = `ws:\/\/${HOST}:${PORT}\/`;  const socket = new WebSocket(API_URL);<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u041b\u043e\u0433\u0438\u043a\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u044f<\/p>\n<pre><code class=\"javascript\">socket.onmessage = function (event) {     const data = JSON.parse(event.data);        const cell = cells[data.cell];        cell.value = data.value; };<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u041b\u043e\u0433\u0438\u043a\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f<\/p>\n<p>\u041d\u0430 \u043a\u0430\u0436\u0434\u043e\u0439 \u044f\u0447\u0435\u0439\u043a\u0435 \u0432\u0438\u0441\u0438\u0442 \u0441\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043d\u0430\u0436\u0430\u0442\u0438\u044f \u043a\u043b\u0430\u0432\u0438\u0448\u0438 (keyup). \u041f\u0440\u0438 \u0432\u0432\u043e\u0434\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u044f\u0447\u0435\u0439\u043a\u0443, \u0441\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u044c \u043e\u0442\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0438 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u0435, \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 &#171;\u0432\u044b\u0442\u0430\u0449\u0438\u0442\u044c&#187; \u0430\u0434\u0440\u0435\u0441 \u044f\u0447\u0435\u0439\u043a\u0438, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043e\u043d\u043e \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u043e \u0438 \u0432\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442.<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043e\u0442\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u044d\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u0441\u043e\u043a\u0435\u0442<\/p>\n<pre><code class=\"javascript\">function onKeyup(event) {     const message = {         cell: event.target.id,         value: event.target.value,     };        socket.send(JSON.stringify(message)); }<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u0412\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438<\/p>\n<ul>\n<li>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u044b<\/p>\n<pre><code class=\"javascript\">function generateTable(table, columns) { const tr = document.createElement(\"tr\");      tr.innerHTML =     \"&lt;td>&lt;\/td>\" +       columns.map((column) => `&lt;td>${column}&lt;\/td>`).join(\"\");      table.appendChild(tr); }<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0441\u0442\u0440\u043e\u043a\u0438<\/p>\n<pre><code class=\"javascript\">function generateRow(table, rowIndex, columns) {     const tr = document.createElement(\"tr\");      tr.innerHTML =         `&lt;td>${rowIndex}&lt;\/td>` +         columns             .map(                 (column) =>                     `&lt;td>&lt;input id=\"${column}${rowIndex}\" type=\"text\">&lt;\/td>`             )             .join(\"\");      table.appendChild(tr);      columns.forEach((column) => {         const cellId = `${column}${rowIndex}`;          const input = document.getElementById(cellId);          input.addEventListener(\"keyup\", onKeyup);          cells[cellId] = input;     }); }<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b<\/p>\n<pre><code class=\"javascript\">function fillTable(table) {     for (let i = 1; i &lt;= ROWS_COUNT; i++) {     generateRow(table, i, COLUMNS);     } }<\/code><\/pre>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>\u041e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0430 \u0442\u0430\u0431\u043b\u0438\u0446\u044b<\/p>\n<p>\u0414\u043b\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0432\u044b\u0437\u043e\u0432\u0435\u043c \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b<\/p>\n<pre><code class=\"javascript\">generateTable(table, COLUMNS);  fillTable(table);<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u0421\u0442\u0438\u043b\u0438<\/p>\n<pre><code class=\"css\">*, html {     margin: 0;     padding: 0;     border: 0;     width: 100%;     height: 100%; }  body {     width: 100%;     height: 100%;      position: relative; }  input {     margin: 2px 0;     padding: 4px 9px;      box-sizing: border-box;      border: 1px solid #ccc;      outline: none; }  input:focus {     border: 1px solid #0096ff; }  table, table td {     border: 1px solid #cccccc; }  td {     height: 20px;     width: 80px;      text-align: center;     vertical-align: middle; }<\/code><\/pre>\n<\/li>\n<\/ul>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043b\u0438 \u0432\u0441\u0435 \u0448\u0430\u0433\u0438 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e, \u0442\u043e \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0432\u044b \u0443\u0432\u0438\u0434\u0438\u0442\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0431 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u043c \u0441\u0442\u0430\u0440\u0442\u0435<\/p>\n<pre><code class=\"bash\">websocket-example git:(main) \u2717 node src\/server.js Server running at &lt;http:\/\/127.0.0.1:8000\/><\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c, \u0435\u0441\u043b\u0438 \u0437\u0430\u0439\u0442\u0438 \u043d\u0430 <a href=\"http:\/\/127.0.0.1:8000\/\" rel=\"noopener noreferrer nofollow\">http:\/\/127.0.0.1:8000\/<\/a> \u043e\u0442\u043a\u0440\u043e\u0435\u0442\u0441\u044f \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u0435\u043c\u0430\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u0430.<\/p>\n<p>\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u043e\u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c, \u043a\u0430\u043a \u0432\u0441\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442. \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435, \u0447\u0442\u043e \u043f\u0440\u0438 \u043d\u043e\u0432\u043e\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u043e\u0442\u043a\u0440\u043e\u0435\u0442\u0441\u044f \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u0430\u044f \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u0430, \u0435\u0441\u043b\u0438 \u0432 \u043d\u0435\u0435 \u0443\u0436\u0435 \u0432\u043d\u043e\u0441\u0438\u043b\u0438\u0441\u044c \u043a\u0430\u043a\u0438\u0435-\u043b\u0438\u0431\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/441\/d93\/aa3\/441d93aa3430d45d3d97d067c8b366dd.png\" width=\"1917\" height=\"1040\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/441\/d93\/aa3\/441d93aa3430d45d3d97d067c8b366dd.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u044c \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u043c\u043e\u0436\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u043b\u043e\u0433\u0438 \u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0438\u0445 \u0441\u043e\u0431\u044b\u0442\u0438\u044f\u0445. \u0422\u0430\u043a\u0436\u0435 \u0432\u0441\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0435\/\u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c\u044b\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0430 \u0432\u043a\u043b\u0430\u0434\u043a\u0435 Network -> WS \u0432 \u0434\u0435\u0432\u0442\u0443\u043b\u0437\u0430\u0445 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430<\/p>\n<details class=\"spoiler\">\n<summary>server.js<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">const ws = require(\"ws\"); const fs = require(\"fs\"); const http = require(\"http\");  const index = fs.readFileSync(\"public\/index.html\", \"utf8\");   const HOST = \"127.0.0.1\"; const PORT = 8000;  const server = http.createServer((req, res) => {     res.writeHead(200);     res.end(index); });  server.listen(PORT, HOST, () => {     console.log(`Server running at http:\/\/${HOST}:${PORT}\/`); });  const wss = new ws.WebSocketServer({ server });  const messages = [];  wss.on(\"connection\", (websocketConnection, req) => {     const ip = req.socket.remoteAddress;     console.log(`[open] Connected ${ip}`);      broadcastMessages(messages, websocketConnection);      websocketConnection.on(\"message\", (message) => {         console.log(\"[message] Received: \" + message);          messages.push(message);          broadcastMessage(message, websocketConnection);     });      websocketConnection.on(\"close\", () => {         console.log(`[close] Disconnected ${ip}`);     }); });   function broadcastMessages(messages, client) {     messages.forEach((message) => {         if (client.readyState === ws.OPEN) {             client.send(message, { binary: false });         }     }); }  function broadcastMessage(message, websocketConnection) {     wss.clients.forEach((client) => {         if (client.readyState === ws.OPEN &amp;&amp; client !== websocketConnection) {             client.send(message, { binary: false });         }     }); } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>index.html<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">&lt;!DOCTYPE html> &lt;html lang=\"en\">     &lt;head>         &lt;style>             *,             html {                 margin: 0;                 padding: 0;                 border: 0;                  width: 100%;                 height: 100%;             }              body {                 width: 100%;                 height: 100%;                  position: relative;             }              input {                 margin: 2px 0;                 padding: 4px 9px;                  box-sizing: border-box;                  border: 1px solid #ccc;                  outline: none;             }              input:focus {                 border: 1px solid #0096ff;             }              table,             table td {                 border: 1px solid #cccccc;             }              td {                 height: 20px;                 width: 80px;                  text-align: center;                 vertical-align: middle;             }         &lt;\/style>     &lt;\/head>     &lt;body>         &lt;table id=\"table\">&lt;\/table>     &lt;\/body>     &lt;script>         const COLUMNS = [\"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"I\", \"K\", \"L\", \"M\", \"O\"];         const ROWS_COUNT = 30;          const table = document.querySelector(\"#table\");          const cells = {};          const HOST = \"127.0.0.1\";         const PORT = \"8000\";          const API_URL = `ws:\/\/${HOST}:${PORT}\/`;          const socket = new WebSocket(API_URL);          socket.onmessage = function (event) {             const data = JSON.parse(event.data);              const cell = cells[data.cell];             cell.value = data.value;         };          function onKeyup(event) {             const message = {                 cell: event.target.id,                 value: event.target.value,             };              socket.send(JSON.stringify(message));         }          function generateTable(table, columns) {             const tr = document.createElement(\"tr\");              tr.innerHTML =                 \"&lt;td>&lt;\/td>\" +                 columns.map((column) => `&lt;td>${column}&lt;\/td>`).join(\"\");              table.appendChild(tr);         }          function generateRow(table, rowIndex, columns) {             const tr = document.createElement(\"tr\");              tr.innerHTML =                 `&lt;td>${rowIndex}&lt;\/td>` +                 columns                     .map(                         (column) =>                             `&lt;td>&lt;input id=\"${column}${rowIndex}\" type=\"text\">&lt;\/td>`                     )                     .join(\"\");              table.appendChild(tr);              columns.forEach((column) => {                 const cellId = `${column}${rowIndex}`;                  const input = document.getElementById(cellId);                  input.addEventListener(\"keyup\", onKeyup);                  cells[cellId] = input;             });         }          function fillTable(table) {             for (let i = 1; i &lt;= ROWS_COUNT; i++) {                 generateRow(table, i, COLUMNS);             }         }          generateTable(table, COLUMNS);          fillTable(table);     &lt;\/script> &lt;\/html> <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041a\u043e\u0434 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0446\u0435\u043b\u0438\u043a\u043e\u043c \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0430 <a href=\"https:\/\/github.com\/mdlufy\/websocket-example\" rel=\"noopener noreferrer nofollow\">Github<\/a><\/p>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u0432\u0441\u0435. \u041d\u0430\u0434\u0435\u044e\u0441\u044c \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u0431\u044b\u043b \u043a\u043e\u043c\u0443-\u0442\u043e \u043f\u043e\u043b\u0435\u0437\u0435\u043d. \u0415\u0441\u043b\u0438 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0442\u0435 \u043e\u0448\u0438\u0431\u043a\u0443 \u0438\u043b\u0438 \u043d\u0435\u0442\u043e\u0447\u043d\u043e\u0441\u0442\u044c, \u043d\u0430\u043f\u0438\u0448\u0438\u0442\u0435 \u043e\u0431 \u044d\u0442\u043e\u043c \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445 \ud83d\ude42<\/p>\n<details class=\"spoiler\">\n<summary>\u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0438<\/summary>\n<div class=\"spoiler__content\">\n<ul>\n<li>\n<p><a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc6455\" rel=\"noopener noreferrer nofollow\">RFC 6455: The WebSocket Protocol<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/websockets.spec.whatwg.org\/#the-websocket-interface\" rel=\"noopener noreferrer nofollow\">Browser websocket-interface<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/ru.wikipedia.org\/wiki\/WebSocket\" rel=\"noopener noreferrer nofollow\">WebSocket<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/learn.javascript.ru\/websocket\" rel=\"noopener noreferrer nofollow\">\u0421\u0435\u0442\u0435\u0432\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b. WebSocket<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/www.youtube.com\/watch?v=Sf7ln3n16ws\" rel=\"noopener noreferrer nofollow\">Websocket \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0430 Node.js<\/a><\/p>\n<\/li>\n<\/ul>\n<\/div>\n<\/details>\n<\/div>\n<\/div>\n<\/div>\n<p> <!----> <!----><\/div>\n<p> <!----> <!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/718780\/\"> https:\/\/habr.com\/ru\/post\/718780\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<h3>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/h3>\n<p>\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442! \u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0413\u0435\u0440\u043c\u0430\u043d \u041f\u0430\u043d\u043e\u0432 \u0438 \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440 &#8212; \u0430\u043d\u0430\u043b\u043e\u0433 Google\u00a0Sheets (\u0432 \u0443\u043f\u0440\u043e\u0449\u0435\u043d\u043d\u043e\u043c \u0432\u0438\u0434\u0435), \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0432\u0435\u0431\u0441\u043e\u043a\u0435\u0442\u043e\u0432, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0430\u043c\u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430\u0445. <\/p>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0446\u0435\u043b\u044c &#8212; \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u043b\u0435\u043d\u0438\u0435, \u043a\u043e\u0434 \u0431\u0443\u0434\u0435\u0442 \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u00ab\u0447\u0438\u0441\u0442\u044b\u043c\u00bb, \u043d\u043e \u0434\u043b\u044f \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u044d\u0442\u043e\u0433\u043e \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Node.js, \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043f\u0430\u043a\u0435\u0442 <a href=\"https:\/\/www.npmjs.com\/package\/ws\" rel=\"noopener noreferrer nofollow\">ws<\/a>, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 API \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0432\u0435\u0431\u0441\u043e\u043a\u0435\u0442\u0430\u043c\u0438 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435.<\/p>\n<h2>\u0417\u0430\u0434\u0430\u0447\u0430<\/h2>\n<p>\u0421\u043e\u0437\u0434\u0430\u0442\u044c \u0442\u0430\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440 \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c\u0438 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f\u043c\u0438:<\/p>\n<p><em>\u0424\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f<\/em><\/p>\n<ul>\n<li>\n<p>\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u044f\u0447\u0435\u0435\u043a \u0442\u0430\u0431\u043b\u0438\u0446\u044b<\/p>\n<\/li>\n<li>\n<p>\u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b<\/p>\n<\/li>\n<li>\n<p>\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438 \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438<\/p>\n<\/li>\n<\/ul>\n<p><em>\u041d\u0430\u0433\u0440\u0443\u0437\u043e\u0447\u043d\u044b\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f<\/em><\/p>\n<ul>\n<li>\n<p>\u0422\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439 \u043f\u043e \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0435 \u043d\u0435\u0442<\/p>\n<\/li>\n<\/ul>\n<h2>\u0422\u0435\u043e\u0440\u0438\u044f. \u041f\u0440\u043e\u0442\u043e\u043a\u043e\u043b Websocket<\/h2>\n<p>\u041f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u00a0<code>WebSocket<\/code>(\u00ab\u0432\u0435\u0431-\u0441\u043e\u043a\u0435\u0442\u00bb) \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e\u0433\u043e \u0434\u0432\u0443\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0435\u0433\u043e \u043e\u0431\u043c\u0435\u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043c\u0435\u0436\u0434\u0443 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c. \u0421\u0435\u0440\u0432\u0435\u0440 \u0432 \u043b\u044e\u0431\u043e\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u0440\u0438\u0441\u043b\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0443, \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e, \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u043b \u043b\u0438 \u0435\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442 \u0438\u043b\u0438 \u043d\u0435\u0442. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0443 \u043d\u0443\u0436\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c <code>handshake<\/code> (\u00ab\u0440\u0443\u043a\u043e\u043f\u043e\u0436\u0430\u0442\u0438\u044f\u00bb)<\/p>\n<p>\u0411\u0440\u0430\u0443\u0437\u0435\u0440, \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0445 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043b\u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u043e\u0431\u043c\u0435\u043d \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043f\u043e Websocket, \u0438 \u0435\u0441\u043b\u0438 \u0434\u0430, \u00ab\u043e\u0431\u0449\u0435\u043d\u0438\u0435\u00bb \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0443\u0436\u0435 \u043f\u043e WebSocket. <\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u041d\u0430 \u043f\u0440\u0438\u043a\u043b\u0430\u0434\u043d\u043e\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442 \u0432 \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0435 UTF-8, \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f JSON \u0444\u043e\u0440\u043c\u0430\u0442. \u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c\u044b\u0435 \u043f\u043e WebSocket, \u043c\u043e\u0436\u043d\u043e \u0432\u043e \u0432\u043a\u043b\u0430\u0434\u043a\u0435 Network -> WS \u0432 \u0434\u0435\u0432\u0442\u0443\u043b\u0437\u0430\u0445 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430.<\/p>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u0435\u0442 TCP. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0434\u0430\u043d\u043d\u044b\u0435 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0438\u0440\u0443\u044e\u0442\u0441\u044f, \u043f\u043e Websocket \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0434\u0430\u0436\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043c\u0430. \u041a\u0430\u0436\u0434\u043e\u0435 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0437\u0431\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0444\u0440\u0435\u0439\u043c\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e \u0441\u0432\u043e\u0435\u0439 \u0441\u0443\u0442\u0438 \u043f\u043e\u0445\u043e\u0436\u0438 \u043d\u0430 http-\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0424\u0440\u0435\u0439\u043c &#8212; \u044d\u0442\u043e \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a + \u00ab\u043f\u043e\u043b\u0435\u0437\u043d\u0430\u044f \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0430\u00bb. \u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0441\u043b\u0443\u0436\u0435\u0431\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0444\u0440\u0435\u0439\u043c\u0435 \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445. \u041f\u043e\u043b\u0435\u0437\u043d\u0430\u044f \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 &#8212; \u044d\u0442\u043e \u043b\u044e\u0431\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u0435 \u0442\u0435\u043a\u0441\u0442\u0443 http-\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0412\u0438\u0434 \u0444\u0440\u0435\u0439\u043c\u0430:<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0412 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u0435\u0441\u0442\u044c API \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0432\u0435\u0431\u0441\u043e\u043a\u0435\u0442\u0430\u043c\u0438, \u0434\u043b\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442 Websocket, \u043f\u0435\u0440\u0435\u0434\u0430\u0432 URL \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430. \u041f\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0438 \u0441 HTTP \u0435\u0441\u0442\u044c \u0434\u0432\u0430 \u0442\u0438\u043f\u0430 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f: \u0441 \u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c (wss) \u0438 \u0431\u0435\u0437 (ws).<\/p>\n<p>\u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043d\u0443\u0436\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043a\u043e\u043b\u0431\u044d\u043a-\u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0443 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430. \u0415\u0441\u0442\u044c 3 \u0442\u0438\u043f\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0434\u043b\u044f \u0441\u0435\u0442\u0435\u0432\u044b\u0445 \u0441\u043e\u0431\u044b\u0442\u0438\u0439: onopen, onerror, onclose \u0438 \u043e\u0434\u0438\u043d \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0434\u043b\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439: onmessage. (\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c <a href=\"https:\/\/websockets.spec.whatwg.org\/#the-websocket-interface\" rel=\"noopener noreferrer nofollow\">\u0442\u0443\u0442<\/a>). <\/p>\n<p>\u0414\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0441\u043e\u043a\u0435\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043c\u0435\u0442\u043e\u0434 send.<\/p>\n<pre><code class=\"javascript\">const ws = new WebSocket('ws:\/\/localhost\/echo');  ws.onopen = event => {     alert('onopen');      ws.send(\"Hello Web Socket!\"); };  ws.onmessage = event => {     alert('onmessage, ' + event.data); };  ws.onclose = event => {     alert('onclose'); };  ws.onerror = event => {     alert('onerror'); };<\/code><\/pre>\n<p>\u041d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u0443\u044e WebSocket \u043a\u043b\u0438\u0435\u043d\u0442-\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <a href=\"https:\/\/github.com\/websockets\/ws\" rel=\"noopener noreferrer nofollow\">ws<\/a> \u0434\u043b\u044f <a href=\"https:\/\/nodejs.org\/\" rel=\"noopener noreferrer nofollow\"><u>Node.js<\/u><\/a>. \u041f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c\u043e\u0435 API \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u0445\u043e\u0436\u0435 \u043d\u0430 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0435.<\/p>\n<p>\u041f\u043e\u043b\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0449\u0438\u0445 \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 WebSocket \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/WebSockets_API#tools\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a><\/p>\n<p>\u0412 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c WebSocket \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u044b\u0439 \u043e\u0431\u043c\u0435\u043d \u0434\u0430\u043d\u043d\u044b\u043c\u0438:<\/p>\n<ul>\n<li>\n<p>\u0418\u0433\u0440\u044b<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u0435\u0442\u0438 \u0438 \u0447\u0430\u0442\u044b<\/p>\n<\/li>\n<li>\n<p>\u0422\u043e\u0440\u0433\u043e\u0432\u044b\u0435 \u043f\u043b\u043e\u0449\u0430\u0434\u043a\u0438<\/p>\n<\/li>\n<li>\n<p>\u0423\u043c\u043d\u044b\u0439 \u0434\u043e\u043c<\/p>\n<\/li>\n<\/ul>\n<h2>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f. \u041d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0430<\/h2>\n<p>\u041f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0443 Node.js. \u0418\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044e \u043f\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0435 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u043d\u0430 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u043c <a href=\"https:\/\/nodejs.org\/\" rel=\"noopener noreferrer nofollow\">\u0441\u0430\u0439\u0442\u0435<\/a><\/p>\n<p>\u041f\u0440\u043e\u0435\u043a\u0442 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u0442\u044c \u0438\u0437 \u0434\u0432\u0443\u0445 \u0444\u0430\u0439\u043b\u043e\u0432:<\/p>\n<ul>\n<li>\n<p>HTML-\u0444\u0430\u0439\u043b \u0441 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u043e\u0439, \u0441\u0442\u0438\u043b\u044f\u043c\u0438 \u0438 \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u043c \u0434\u043b\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0439 \u0447\u0430\u0441\u0442\u0438<\/p>\n<\/li>\n<li>\n<p>JS-\u0444\u0430\u0439\u043b \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u043e\u0439, \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0449\u0435\u0439 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043f\u043e \u0441\u0435\u0442\u0438<\/p>\n<\/li>\n<\/ul>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u043a\u0435\u043b\u0435\u0442 \u043f\u0440\u043e\u0435\u043a\u0442\u0430:<\/p>\n<ol>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u0430\u0442\u0430\u043b\u043e\u0433 \u043f\u043e\u0434 \u043f\u0440\u043e\u0435\u043a\u0442.<\/p>\n<\/li>\n<li>\n<p>\u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u043d\u043e\u0432\u044b\u0439 git-\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0432 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u043c \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435.<\/p>\n<\/li>\n<li>\n<p>\u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u043d\u043e\u0432\u044b\u0439 npm-\u043f\u0430\u043a\u0435\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043a\u043e\u0434 \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0430\u043a\u0435\u0442\u044b. \u0418\u0437 \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0430\u043a\u0435\u0442 <a href=\"https:\/\/www.npmjs.com\/package\/ws\" rel=\"noopener noreferrer nofollow\">ws<\/a>.<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b .gitignore, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u043f\u0438\u0448\u0435\u043c \u043a\u0430\u0442\u0430\u043b\u043e\u0433 &#171;node_modules&#187;, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0442\u044f\u043d\u0443\u0442\u044c \u043a\u0430\u0442\u0430\u043b\u043e\u0433 \u0441 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u043c\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438 \u0432 git \u043d\u0435 \u0441\u0442\u043e\u0438\u0442.<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"bash\"># \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u0430\u0442\u0430\u043b\u043e\u0433 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u0432 \u043d\u0435\u0433\u043e mkdir websocket-example &amp;&amp; cd websocket-example  # \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c git-\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 git init  # \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c npm-\u043f\u0430\u043a\u0435\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043a\u043e\u0434 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 npm init -y  # \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 WebSocket \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 npm install ws  # \u0423\u043a\u0430\u0436\u0435\u043c git \u043d\u0435 \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u043a\u0430\u0442\u0430\u043b\u043e\u0433 \u0441 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u043c\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438 touch .gitignore &amp;&amp; echo \"node_modules\" >> .gitignore<\/code><\/pre>\n<p>\u0411\u0430\u0437\u043e\u0432\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043e, \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0430\u0442\u044c \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>\u041e\u0440\u0433\u0430\u043d\u0438\u0437\u0443\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0430:<\/p>\n<p>node_modules<br \/>public\/index.html<br \/>src\/server.js<br \/>.gitignore<br \/>package\u2011lock.json<br \/>package.json<\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0437\u0430\u0434\u0430\u0447\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430:<\/p>\n<ul>\n<li>\n<p>\u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439.<\/p>\n<\/li>\n<li>\n<p>\u041e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043f\u0440\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u0440\u0430\u0437\u043e\u0441\u043b\u0430\u0442\u044c \u0435\u0433\u043e \u0432\u0441\u0435\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044b\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438.<\/p>\n<h3>server.js<\/h3>\n<ol>\n<li>\n<p>\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/p>\n<ul>\n<li>\n<p>\u041e\u0431\u044a\u044f\u0432\u0438\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438<\/p>\n<pre><code class=\"javascript\">const ws = require(\"ws\"); const fs = require(\"fs\"); const http = require(\"http\");<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043c \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c http-\u0441\u0435\u0440\u0432\u0435\u0440<\/p>\n<pre><code class=\"javascript\">const index = fs.readFileSync(\"public\/index.html\", \"utf8\");<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c http-\u0441\u0435\u0440\u0432\u0435\u0440<\/p>\n<ol>\n<li>\n<p>\u0417\u0430\u0434\u0430\u0435\u043c \u0430\u0434\u0440\u0435\u0441 \u0445\u043e\u0441\u0442\u0430 \u0438 \u043f\u043e\u0440\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0441\u043b\u0443\u0448\u0438\u0432\u0430\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440.<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0430\u0435\u043c \u043d\u043e\u0432\u044b\u0439 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u0432 \u043a\u043e\u043b\u0431\u044d\u043a\u0435 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c, \u0447\u0442\u043e \u043d\u0430 \u0432\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0441\u0435\u0440\u0432\u0435\u0440 \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0439 index.html \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442 \u0441 200 \u043a\u043e\u0434\u043e\u043c \u043e\u0442\u0432\u0435\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0441\u0435\u0440\u0432\u0435\u0440, \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u043d\u0430\u0447\u0430\u043b \u043f\u0440\u043e\u0441\u043b\u0443\u0448\u0438\u0432\u0430\u0442\u044c \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u0439 \u0445\u043e\u0441\u0442 \u0438 \u043f\u043e\u0440\u0442. \u0412\u044b\u0432\u0435\u0434\u0435\u043c \u0432 \u043b\u043e\u0433\u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e\u0431 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u043c \u043d\u0430\u0447\u0430\u043b\u0435 \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u0435\u0440\u0432\u0435\u0440\u0430.<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"javascript\">const HOST = \"127.0.0.1\"; const PORT = 8000;  const server = http.createServer((req, res) => {     res.writeHead(200);     res.end(index); });  server.listen(PORT, HOST, () => {     console.log(`Server running at http:\/\/${HOST}:${PORT}\/`); });<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c Websocket-\u0441\u0435\u0440\u0432\u0435\u0440, \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u043f\u043e\u0432\u0435\u0440\u0445 http-\u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/p>\n<pre><code class=\"javascript\">const wss = new ws.WebSocketServer({ server });<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043c\u0430\u0441\u0441\u0438\u0432 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439<\/p>\n<pre><code class=\"javascript\">const messages = [];<\/code><\/pre>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>\u041b\u043e\u0433\u0438\u043a\u0430 \u0441\u0435\u0442\u0435\u0432\u043e\u0433\u043e \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f<\/p>\n<ul>\n<li>\n<p>\u041d\u043e\u0432\u044b\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f<\/p>\n<pre><code class=\"javascript\">\/*   \u041a\u043b\u0430\u0441\u0441 WebSocketServer \u0438\u043c\u0435\u0435\u0442 \u043c\u0435\u0442\u043e\u0434 on, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0439 \u043f\u043e\u0433\u0440\u0443\u0437\u0438\u0442\u044c\u0441\u044f   \u0432\u043d\u0443\u0442\u0440\u044c \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0433\u043e \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0438 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043a\u0430\u043a\u0438\u0445-\u043b\u0438\u0431\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u0439.    \u041c\u0435\u0442\u043e\u0434 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043f\u0435\u0440\u0432\u044b\u043c \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u043c \u0441\u043e\u0431\u044b\u0442\u0438\u0435, \u0430 \u0432\u0442\u043e\u0440\u044b\u043c \u043a\u043e\u043b\u0431\u044d\u043a \u043d\u0430 \u044d\u0442\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u0435    \u0422\u0438\u043f\u044b \u0441\u043e\u0431\u044b\u0442\u0438\u0439: \"connection\" | \"message\" | \"error\" | \"close\"    \u0412\u0442\u043e\u0440\u044b\u043c \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u043a\u043e\u043b\u0431\u044d\u043a, \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u0443\u0434\u0443\u0442   \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0438 \u0437\u0430\u043f\u0440\u043e\u0441, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0439 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043b\u0443\u0436\u0435\u0431\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e *\/  wss.on(\"connection\", (websocketConnection, req) => {     \/\/ \u0437\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0435\u0442 \u043b\u043e\u0433\u0438\u043a\u0430 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f });<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f<\/p>\n<p>\u041f\u0440\u0438 \u043d\u043e\u0432\u043e\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u0431\u0443\u0434\u0435\u043c \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u044c \u0432 \u043b\u043e\u0433\u0438 ip-\u0430\u0434\u0440\u0435\u0441 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0432\u0448\u0435\u0433\u043e\u0441\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0438 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0442\u044c \u0440\u0430\u0441\u0441\u044b\u043b\u043a\u0443 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439.<\/p>\n<pre><code class=\"javascript\">wss.on(\"connection\", (websocketConnection, req) => {     const ip = req.socket.remoteAddress;      console.log(`[open] Connected ${ip}`);  broadcastMessages(messages, websocketConnection); });<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f<\/p>\n<p>\u041f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0435\u043c \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u044c \u0435\u0433\u043e \u0432 \u043b\u043e\u0433\u0438, \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0432 \u043c\u0430\u0441\u0441\u0438\u0432 \u0443\u0436\u0435 \u0438\u043c\u0435\u044e\u0449\u0438\u0445\u0441\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0438 \u0440\u0430\u0441\u0441\u044b\u043b\u0430\u0442\u044c \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c.<\/p>\n<pre><code class=\"javascript\">wss.on(\"connection\", (websocketConnection, req) => {     const ip = req.socket.remoteAddress;     console.log(`[open] Connected ${ip}`);  broadcastMessages(messages, websocketConnection);      websocketConnection.on(\"message\", (message) => {         console.log(\"[message] Received: \" + message);  messages.push(message);          broadcastMessage(message, websocketConnection);     }); });<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430<\/p>\n<p>\u041f\u0440\u0438 \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0431\u0443\u0434\u0435\u043c \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u044c \u0432 \u043b\u043e\u0433\u0438 \u0435\u0433\u043e ip-\u0430\u0434\u0440\u0435\u0441.<\/p>\n<pre><code class=\"javascript\">wss.on(\"connection\", (websocketConnection, req) => {     const ip = req.socket.remoteAddress;     console.log(`[open] Connected ${ip}`);  broadcastMessages(messages, websocketConnection);      websocketConnection.on(\"message\", (message) => {         console.log(\"[message] Received: \" + message);  messages.push(message);          broadcastMessage(message, websocketConnection);     });      websocketConnection.on(\"close\", () => {         console.log(`[close] Disconnected ${ip}`);     }); });<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u0412\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438<\/p>\n<ul>\n<li>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0440\u0430\u0441\u0441\u044b\u043b\u043a\u0438 \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439<\/p>\n<pre><code class=\"javascript\">function broadcastMessages(messages, client) {     messages.forEach((message) => {         if (client.readyState === ws.OPEN) {             client.send(message, { binary: false });         }     }); }<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0440\u0430\u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f<\/p>\n<pre><code class=\"javascript\">\/*   \u0414\u043e\u0441\u0442\u0443\u043f \u043a \u0441\u043f\u0438\u0441\u043a\u0443 \u0442\u0435\u043a\u0443\u0449\u0438\u0445 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f   \u0447\u0435\u0440\u0435\u0437 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e clients \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430.    \u041d\u0435 \u0437\u0430\u0431\u0443\u0434\u0435\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c, \u0447\u0442\u043e \u043a\u043b\u0438\u0435\u043d\u0442 \u0433\u043e\u0442\u043e\u0432 \u043a \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044e \u0438 \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u0430,   \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0432\u0448\u0435\u0433\u043e \u044d\u0442\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u0435 (\u0443 \u043d\u0435\u0433\u043e \u043e\u043d\u043e \u0443\u0436\u0435 \u0435\u0441\u0442\u044c). *\/  function broadcastMessage(message, websocketConnection) {     wss.clients.forEach((client) => {         if (client.readyState === ws.OPEN &amp;&amp; client !== websocketConnection) {             client.send(message, { binary: false });         }     }); }<\/code><\/pre>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f.<\/p>\n<h3>index.html<\/h3>\n<p>\u0412 \u043a\u043b\u0438\u0435\u043d\u0442\u043a\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0431\u0443\u0434\u0435\u0442 \u0442\u0430\u0431\u043b\u0438\u0446\u0430, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u043c\u0438. \u041f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043d\u0430 \u043b\u044e\u0431\u0443\u044e \u044f\u0447\u0435\u0439\u043a\u0443, \u043e\u043d\u0430 \u043f\u043e\u0434\u0441\u0432\u0435\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0438 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0434\u043b\u044f \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.<\/p>\n<figure class=\"\"><figcaption><\/figcaption><\/figure>\n<p>\u0412 public\/index.html \u0431\u0443\u0434\u0435\u0442 \u0432\u0441\u0435: \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0430, \u0441\u0442\u0438\u043b\u0438, \u0434\u0438\u043d\u0430\u043c\u0438\u043a\u0430. \u042d\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0438\u043c\u0435\u043d\u043d\u043e \u0432 index.html, \u0442\u0430\u043a \u043a\u0430\u043a \u0441\u0435\u0440\u0432\u0435\u0440 \u043e\u0442\u0434\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0433\u043e.<\/p>\n<ul>\n<li>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0441\u0442\u0440\u0443\u0442\u0443\u0440\u0443 html \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430<\/p>\n<pre><code class=\"xml\">&lt;!DOCTYPE html> &lt;html lang=\"en\">     &lt;head>         &lt;style>          &lt;! -- \u0437\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0443\u0442 \u0441\u0442\u0438\u043b\u0438 -->         &lt;\/style>     &lt;\/head>     &lt;body>   &lt;! -- \u0442\u0430\u0431\u043b\u0438\u0446\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c\u0441\u044f -->         &lt;table id=\"table\">&lt;\/table>     &lt;\/body>     &lt;script>     &lt;! -- \u0437\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0435\u0442 \u043b\u043e\u0433\u0438\u043a\u0430 -->     &lt;\/script> &lt;\/html> <\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u0421\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0443\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0443<\/p>\n<pre><code class=\"javascript\">const COLUMNS = [\"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"I\", \"K\", \"L\", \"M\", \"O\"]; const ROWS_COUNT = 30;  const table = document.querySelector(\"#table\");<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u044f\u0447\u0435\u0435\u043a \u0442\u0430\u0431\u043b\u0438\u0446\u044b<\/p>\n<pre><code class=\"javascript\">const cells = {};<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u0418\u043d\u0438\u0446\u0438\u0438\u0440\u0443\u0435\u043c Websocket-\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c<\/p>\n<pre><code class=\"javascript\">const HOST = \"127.0.0.1\"; const PORT = \"8000\";  const API_URL = `ws:\/\/${HOST}:${PORT}\/`;  const socket = new WebSocket(API_URL);<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u041b\u043e\u0433\u0438\u043a\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u044f<\/p>\n<pre><code class=\"javascript\">socket.onmessage = function (event) {     const data = JSON.parse(event.data);        const cell = cells[data.cell];        cell.value = data.value; };<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p>\u041b\u043e\u0433\u0438\u043a\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f<\/p>\n<p>\u041d\u0430 \u043a\u0430\u0436\u0434\u043e\u0439 \u044f\u0447\u0435\u0439\u043a\u0435 \u0432\u0438\u0441\u0438\u0442 \u0441\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043d\u0430\u0436\u0430\u0442\u0438\u044f \u043a\u043b\u0430\u0432\u0438\u0448\u0438 (keyup). <\/p>\n<\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-345855","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/345855","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=345855"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/345855\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=345855"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=345855"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=345855"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}