From 2a693fed8f1c0d0174d49ae63de8dcc7fd18b944 Mon Sep 17 00:00:00 2001 From: LycheeEng Date: Sat, 27 Jul 2019 20:52:30 +0800 Subject: [PATCH 1/6] add new files --- 5-network/10-long-polling/article.md | 94 ++++++++++++++++++ 5-network/10-long-polling/long-polling.png | Bin 0 -> 18962 bytes 5-network/10-long-polling/long-polling@2x.png | Bin 0 -> 48832 bytes .../10-long-polling/longpoll.view/browser.js | 54 ++++++++++ .../10-long-polling/longpoll.view/index.html | 18 ++++ .../10-long-polling/longpoll.view/server.js | 87 ++++++++++++++++ 6 files changed, 253 insertions(+) create mode 100644 5-network/10-long-polling/article.md create mode 100644 5-network/10-long-polling/long-polling.png create mode 100644 5-network/10-long-polling/long-polling@2x.png create mode 100644 5-network/10-long-polling/longpoll.view/browser.js create mode 100644 5-network/10-long-polling/longpoll.view/index.html create mode 100644 5-network/10-long-polling/longpoll.view/server.js diff --git a/5-network/10-long-polling/article.md b/5-network/10-long-polling/article.md new file mode 100644 index 0000000000..19624e097b --- /dev/null +++ b/5-network/10-long-polling/article.md @@ -0,0 +1,94 @@ +# Long polling + +Long polling is the simplest way of having persistent connection with server, that doesn't use any specific protocol like WebSocket or Server Side Events. + +Being very easy to implement, it's also good enough in a lot of cases. + +## Regular Polling + +The simplest way to get new information from the server is polling. + +That is, periodical requests to the server: "Hello, I'm here, do you have any information for me?". For example, once in 10 seconds. + +In response, the server first takes a notice to itself that the client is online, and second - sends a packet of messages it got till that moment. + +That works, but there are downsides: +1. Messages are passed with a delay up to 10 seconds (between requests). +2. Even if there are no messages, the server is bombed with requests every 10 seconds. That's quite a load to handle for backend, speaking performance-wise. + +So, if we're talking about a very small service, the approach may be viable, but generally, it needs an improvement. + +## Long polling + +So-called "long polling" is a much better way to poll the server. + +It's also very easy to implement, and delivers messages without delays. + +The flow: + +1. A request is sent to the server. +2. The server doesn't close the connection until it has a message. +3. When a message appears - the server responds to the request with the data. +4. The browser makes a new request immediately. + +The situation when the browser sent a request and has a pending connection with the server, is standard for this method. Only when a message is delivered, the connection is reestablished. + +![](long-polling.png) + +If the connection is lost, because of, say, a network error, the browser immediately sends a new request. + +A sketch of client-side `subscribe` function that makes long requests: + +```js +async function subscribe() { + let response = await fetch("/subscribe"); + + if (response.status == 502) { + // Connection timeout error, + // may happen when the connection was pending for too long, and the remote server or a proxy closed it + // let's reconnect + await subscribe(); + } else if (response.status != 200) { + // Show Error + showMessage(response.statusText); + // Reconnect in one second + await new Promise(resolve => setTimeout(resolve, 1000)); + await subscribe(); + } else { + // Got message + let message = await response.text(); + showMessage(message); + await subscribe(); + } +} + +subscribe(); +``` + +As you can see, `subscribe` function makes a fetch, then waits for the response, handles it and calls itself again. + +```warn header="Server should be ok with many pending connections" +The server architecture must be able to work with many pending connections. + +Certain server architectures run a process per connect. For many connections there will be as many processes, and each process takes a lot of memory. So many connections just consume it all. + +That's often the case for backends written in PHP, Ruby languages, but technically isn't a language, but rather implementation issue. + +Backends written using Node.js usually don't have such problems. +``` + +## Demo: a chat + +Here's a demo: + +[codetabs src="longpoll" height=500] + +## Area of usage + +Long polling works great in situations when messages are rare. + +If messages come very often, then the chart of requesting-receiving messages, painted above, becomes saw-like. + +Every message is a separate request, supplied with headers, authentication overhead, and so on. + +So, in this case, another method is preferred, such as [Websocket](info:websocket) or [Server Sent Events](info:server-sent-events). diff --git a/5-network/10-long-polling/long-polling.png b/5-network/10-long-polling/long-polling.png new file mode 100644 index 0000000000000000000000000000000000000000..433e159f8bf434afcd05cf9aa4baae85b7c072a7 GIT binary patch literal 18962 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 literal 0 HcmV?d00001 diff --git a/5-network/10-long-polling/long-polling@2x.png b/5-network/10-long-polling/long-polling@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9d4da477c7405ea198dfd40a4d64038229b261a7 GIT binary patch literal 48832 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 setTimeout(resolve, 1000)); + await subscribe(); + } else { + // Got message + let message = await response.text(); + showMessage(message); + await subscribe(); + } + } + + subscribe(); + +} diff --git a/5-network/10-long-polling/longpoll.view/index.html b/5-network/10-long-polling/longpoll.view/index.html new file mode 100644 index 0000000000..7452c18386 --- /dev/null +++ b/5-network/10-long-polling/longpoll.view/index.html @@ -0,0 +1,18 @@ + + + +All visitors of this page will see messages of each other. + +
+ + +
+ +
+
+ + diff --git a/5-network/10-long-polling/longpoll.view/server.js b/5-network/10-long-polling/longpoll.view/server.js new file mode 100644 index 0000000000..c3903e3750 --- /dev/null +++ b/5-network/10-long-polling/longpoll.view/server.js @@ -0,0 +1,87 @@ +let http = require('http'); +let url = require('url'); +let querystring = require('querystring'); +let static = require('node-static'); + +let fileServer = new static.Server('.'); + +let subscribers = Object.create(null); + +function onSubscribe(req, res) { + let id = Math.random(); + + res.setHeader('Content-Type', 'text/plain;charset=utf-8'); + res.setHeader("Cache-Control", "no-cache, must-revalidate"); + + subscribers[id] = res; + + req.on('close', function() { + delete subscribers[id]; + }); + +} + +function publish(message) { + + for (let id in subscribers) { + let res = subscribers[id]; + res.end(message); + } + + subscribers = Object.create(null); +} + +function accept(req, res) { + let urlParsed = url.parse(req.url, true); + + // new client wants messages + if (urlParsed.pathname == '/subscribe') { + onSubscribe(req, res); + return; + } + + // sending a message + if (urlParsed.pathname == '/publish' && req.method == 'POST') { + // accept POST + req.setEncoding('utf8'); + let message = ''; + req.on('data', function(chunk) { + message += chunk; + }).on('end', function() { + publish(message); // publish it to everyone + res.end("ok"); + }); + + return; + } + + // the rest is static + fileServer.serve(req, res); + +} + +function close() { + for (let id in subscribers) { + let res = subscribers[id]; + res.end(); + } +} + +// ----------------------------------- + +if (!module.parent) { + http.createServer(accept).listen(8080); + console.log('Server running on port 8080'); +} else { + exports.accept = accept; + + if (process.send) { + process.on('message', (msg) => { + if (msg === 'shutdown') { + close(); + } + }); + } + + process.on('SIGINT', close); +} From cdcbfe9b133921b03b64833dab365e2236e42714 Mon Sep 17 00:00:00 2001 From: LycheeEng Date: Sat, 27 Jul 2019 20:58:27 +0800 Subject: [PATCH 2/6] translate browser.js --- .../10-long-polling/longpoll.view/browser.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/5-network/10-long-polling/longpoll.view/browser.js b/5-network/10-long-polling/longpoll.view/browser.js index 3a66aa5c6d..7ac024a786 100644 --- a/5-network/10-long-polling/longpoll.view/browser.js +++ b/5-network/10-long-polling/longpoll.view/browser.js @@ -1,4 +1,4 @@ -// Sending messages, a simple POST +// 发送消息,一个简单的 POST 请求 function PublishForm(form, url) { function sendMessage(message) { @@ -18,7 +18,7 @@ function PublishForm(form, url) { }; } -// Receiving messages with long polling +// 通过长轮询(long polling)接收消息 function SubscribePane(elem, url) { function showMessage(message) { @@ -31,18 +31,18 @@ function SubscribePane(elem, url) { let response = await fetch(url); if (response.status == 502) { - // Connection timeout - // happens when the connection was pending for too long - // let's reconnect + // 连接超时 + // 当连接等待时间过长时发生 + // 重新连接 await subscribe(); } else if (response.status != 200) { - // Show Error + // 显示错误 showMessage(response.statusText); - // Reconnect in one second + // 1 秒后重新连接 await new Promise(resolve => setTimeout(resolve, 1000)); await subscribe(); } else { - // Got message + // 得到消息 let message = await response.text(); showMessage(message); await subscribe(); From 78b7da546478f990274758387604583608166b22 Mon Sep 17 00:00:00 2001 From: LycheeEng Date: Sat, 27 Jul 2019 20:59:33 +0800 Subject: [PATCH 3/6] translate index.html --- 5-network/10-long-polling/longpoll.view/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/5-network/10-long-polling/longpoll.view/index.html b/5-network/10-long-polling/longpoll.view/index.html index 7452c18386..5c65d7b27c 100644 --- a/5-network/10-long-polling/longpoll.view/index.html +++ b/5-network/10-long-polling/longpoll.view/index.html @@ -13,6 +13,6 @@ From cea32726808d653578939317c5d5141b80954ba5 Mon Sep 17 00:00:00 2001 From: LycheeEng Date: Sat, 27 Jul 2019 21:01:22 +0800 Subject: [PATCH 4/6] server.js --- 5-network/10-long-polling/longpoll.view/server.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/5-network/10-long-polling/longpoll.view/server.js b/5-network/10-long-polling/longpoll.view/server.js index c3903e3750..e7d91c52e9 100644 --- a/5-network/10-long-polling/longpoll.view/server.js +++ b/5-network/10-long-polling/longpoll.view/server.js @@ -34,28 +34,28 @@ function publish(message) { function accept(req, res) { let urlParsed = url.parse(req.url, true); - // new client wants messages + // 新客户端想要获取消息 if (urlParsed.pathname == '/subscribe') { onSubscribe(req, res); return; } - // sending a message + // 发送消息 if (urlParsed.pathname == '/publish' && req.method == 'POST') { - // accept POST + // 接受 POST 请求 req.setEncoding('utf8'); let message = ''; req.on('data', function(chunk) { message += chunk; }).on('end', function() { - publish(message); // publish it to everyone + publish(message); // 广播给所有人 res.end("ok"); }); return; } - // the rest is static + // 剩下的是静态的 fileServer.serve(req, res); } From bbdf04a07d6834114393efd62e64d079802faa30 Mon Sep 17 00:00:00 2001 From: LycheeEng Date: Sat, 27 Jul 2019 22:08:22 +0800 Subject: [PATCH 5/6] translate article.md --- 5-network/10-long-polling/article.md | 82 ++++++++++++++-------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/5-network/10-long-polling/article.md b/5-network/10-long-polling/article.md index 19624e097b..950db7b70c 100644 --- a/5-network/10-long-polling/article.md +++ b/5-network/10-long-polling/article.md @@ -1,61 +1,61 @@ -# Long polling +# 长轮询(long polling) -Long polling is the simplest way of having persistent connection with server, that doesn't use any specific protocol like WebSocket or Server Side Events. +长轮询是与服务器建立持久连接的最简单方法,它不使用任何特定协议,比如 WebSocket 或者服务端事件(Server Side Events)。 -Being very easy to implement, it's also good enough in a lot of cases. +它很容易实现,在很多场景下也很好用。 -## Regular Polling +## 普通轮询(regular Polling) -The simplest way to get new information from the server is polling. +最简单的从服务器获取新信息的方式就是轮询。 -That is, periodical requests to the server: "Hello, I'm here, do you have any information for me?". For example, once in 10 seconds. +也就是说,定期向服务器发出请求:“Hello, I'm here, do you have any information for me?”。例如,10 秒发送一次。 -In response, the server first takes a notice to itself that the client is online, and second - sends a packet of messages it got till that moment. +作为响应,服务器首先通知自己客户端在线,然后第二次 —— 发送直到那个时刻的消息包。 -That works, but there are downsides: -1. Messages are passed with a delay up to 10 seconds (between requests). -2. Even if there are no messages, the server is bombed with requests every 10 seconds. That's quite a load to handle for backend, speaking performance-wise. +这很有效,但是也有些缺点: +1. 消息的传递时间最长为 10 秒(每个请求之间)。 +2. 即使没有消息,服务器也会每隔 10 秒被请求轰炸一次。对于后端来说,出于性能的考量,这是一个非常大的负担。 -So, if we're talking about a very small service, the approach may be viable, but generally, it needs an improvement. +因此,如果我们讨论的是一个小型的服务,这种方法是可行的,但是一般来说,它需要一些改进。 -## Long polling +## 长轮询(long polling) -So-called "long polling" is a much better way to poll the server. +所谓“长轮询”是一种更好的轮询服务器的方法。 -It's also very easy to implement, and delivers messages without delays. +它非常容易实现,并且可以无延迟地传递消息。 -The flow: +其流程为: -1. A request is sent to the server. -2. The server doesn't close the connection until it has a message. -3. When a message appears - the server responds to the request with the data. -4. The browser makes a new request immediately. +1. 发送请求到服务器。 +2. 服务器在有消息之前不会关闭连接。 +3. 当消息出现 —— 服务器响应请求,并携带相应的数据。 +4. 浏览器马上创建一个新的请求。 -The situation when the browser sent a request and has a pending connection with the server, is standard for this method. Only when a message is delivered, the connection is reestablished. +当浏览器发送一个请求并与服务器建立挂起(pending)连接的情况是此方法的标准。仅仅在传递消息时,才会重新建立连接。 ![](long-polling.png) -If the connection is lost, because of, say, a network error, the browser immediately sends a new request. +如果连接丢失,可能是因为网络错误,浏览器立即发送一个新请求。 -A sketch of client-side `subscribe` function that makes long requests: +发出长请求的客户端 `subscribe` 函数的草图: ```js async function subscribe() { let response = await fetch("/subscribe"); if (response.status == 502) { - // Connection timeout error, - // may happen when the connection was pending for too long, and the remote server or a proxy closed it - // let's reconnect + // 连接超时错误, + // 当连接挂起太长可能会发生,远程服务器或者代理会关闭它 + // 重新连接 await subscribe(); } else if (response.status != 200) { - // Show Error + // 显示错误 showMessage(response.statusText); - // Reconnect in one second + // 1 秒后重连 await new Promise(resolve => setTimeout(resolve, 1000)); await subscribe(); } else { - // Got message + // 得到消息 let message = await response.text(); showMessage(message); await subscribe(); @@ -65,30 +65,30 @@ async function subscribe() { subscribe(); ``` -As you can see, `subscribe` function makes a fetch, then waits for the response, handles it and calls itself again. +你可以看到,`subscribe` 函数发起 fetch 请求,然后等待请求响应并处理它,然后再调用自己。 -```warn header="Server should be ok with many pending connections" -The server architecture must be able to work with many pending connections. +```warn header="对于许多的挂起连接,服务器也应该能够很好的处理" +服务器架构必须能够处理许多挂起连接。 -Certain server architectures run a process per connect. For many connections there will be as many processes, and each process takes a lot of memory. So many connections just consume it all. +某些服务器架构是每个连接对应一个进程。对于许多连接的情况,可能会有许多进程,每个进程占用很多内存。因此连接越多消耗也就越多。 -That's often the case for backends written in PHP, Ruby languages, but technically isn't a language, but rather implementation issue. +这种情况通常是对于使用 PHP,Ruby 语言的后端,但是从技术上来说,它不是一种语言,而是实现的问题。 -Backends written using Node.js usually don't have such problems. +使用 Node.js 写的后端通常不会出现这样的问题。 ``` -## Demo: a chat +## Demo:chat -Here's a demo: +这是一个 demo: [codetabs src="longpoll" height=500] -## Area of usage +## 使用场景 -Long polling works great in situations when messages are rare. +在消息很少的情况下,长轮询很有效。 -If messages come very often, then the chart of requesting-receiving messages, painted above, becomes saw-like. +如果消息比较频繁,那么上面描绘的请求接收(requesting-receiving)消息的图表就会变成锯状(saw-like)。 -Every message is a separate request, supplied with headers, authentication overhead, and so on. +每条消息都是单独的请求,提供 headers,authentication overhead 等等。 -So, in this case, another method is preferred, such as [Websocket](info:websocket) or [Server Sent Events](info:server-sent-events). +因此,在这种情况下,首选另一种方法,例如:[Websocket](info:websocket) 或者 [Server Sent Events](info:server-sent-events)。 From a65196e44467eaf41beba174b8b6851b5fa00ee2 Mon Sep 17 00:00:00 2001 From: LycheeEng Date: Mon, 29 Jul 2019 23:22:18 +0800 Subject: [PATCH 6/6] update article with review suggestions --- 5-network/10-long-polling/article.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/5-network/10-long-polling/article.md b/5-network/10-long-polling/article.md index 950db7b70c..772a321a08 100644 --- a/5-network/10-long-polling/article.md +++ b/5-network/10-long-polling/article.md @@ -13,7 +13,7 @@ 作为响应,服务器首先通知自己客户端在线,然后第二次 —— 发送直到那个时刻的消息包。 这很有效,但是也有些缺点: -1. 消息的传递时间最长为 10 秒(每个请求之间)。 +1. 消息的传递时间长达 10 秒(每个请求之间)。 2. 即使没有消息,服务器也会每隔 10 秒被请求轰炸一次。对于后端来说,出于性能的考量,这是一个非常大的负担。 因此,如果我们讨论的是一个小型的服务,这种方法是可行的,但是一般来说,它需要一些改进。 @@ -89,6 +89,6 @@ subscribe(); 如果消息比较频繁,那么上面描绘的请求接收(requesting-receiving)消息的图表就会变成锯状(saw-like)。 -每条消息都是单独的请求,提供 headers,authentication overhead 等等。 +每条消息都是单独的请求,带有 headers,authentication 等开销。 因此,在这种情况下,首选另一种方法,例如:[Websocket](info:websocket) 或者 [Server Sent Events](info:server-sent-events)。