XMLHttpRequest 创建几个传出端口 - 为啥?

Posted

技术标签:

【中文标题】XMLHttpRequest 创建几个传出端口 - 为啥?【英文标题】:XMLHttpRequest creates several outgoing ports - why?XMLHttpRequest 创建几个传出端口 - 为什么? 【发布时间】:2015-12-09 21:49:44 【问题描述】:

我是 javascript 和 AJAX 的新手。对一般网络通信来说也是新手。

我正在尝试创建一个与 Python 服务器通信的动态更新网页。我一直在本地测试所有内容,到目前为止一切正常。我认为。

Python 服务器在 localhost 端口 8000 上提供“page.html”。HTML 页面使用 AJAX 和 XMLHttpRequest 将数据 POST 到服务器。我可以向服务器发送数据就好了。

问题出在这里:我的服务器表明,对于每个帖子,都会打开一个新的客户端端口。这让我很害怕,因为我习惯了在单个端口上进行通信的 TCP 套接字。

这是服务器代码(server.py):

import cgi
import http.server
import urllib
import socketserver

class ServerHandler(http.server.SimpleHTTPRequestHandler):
    def do_POST(self):
        ctype, pdict = cgi.parse_header(self.headers['content-type'])
        length = int(self.headers['content-length'])
        postvars = urllib.parse.parse_qs(self.rfile.read(length).decode('utf-8'))
        ip, port = self.client_address
        print(ip, "@", port, "-->", postvars)

def start_server():
    httpServer = socketserver.TCPServer(("", 8000), ServerHandler)
    httpServer.serve_forever()

if __name__ == "__main__":
    start_server()

这是 HTML 代码 (page.html):

<html>
    <head></head>
    <body>
        <script type="text/javascript">
            function send_receive() 
                var http = new XMLHttpRequest();
                var data = document.test_form.data.value;
                var params = "data=" + data.toString();

                http.open("POST", "page.html", true);
                http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
                http.setRequestHeader("Content-length", params.length);
                http.setRequestHeader("Connection", "close");
                http.send(params);
            
        </script>

        <form name=test_form>
            Data: <input type="text" name="data" value="1">
            <input type=button onClick="send_receive();" value="Send"><br /><br />
        </form>
    </body>
</html>

这是在页面上发送 1 到 6 后的服务器输出。

127.0.0.1 @ 52884 --> 'data': ['1']
127.0.0.1 @ 52885 --> 'data': ['2']
127.0.0.1 @ 52886 --> 'data': ['3']
127.0.0.1 @ 52887 --> 'data': ['4']
127.0.0.1 @ 52888 --> 'data': ['5']
127.0.0.1 @ 52889 --> 'data': ['6']

要测试启动 server.py,然后转到浏览器并输入

http://localhost:8000/page.html OR http://127.0.0.1:8000/page.html

您可以看到每个 POST 的端口增量。有什么我做错了吗?我觉得 XHR 挥之不去,需要关闭,但从我在网上阅读的内容来看,显然每个 POST 都需要创建一个新的 XHR。谢谢!

【问题讨论】:

【参考方案1】:

没关系。 服务器从其可用端口池中为此类端口选择一个新的源端口 - 这确保了每个 HTTP 请求和它建立的相应 TCP 连接的唯一 TCP connection tuple。 (服务器选择它用于传入连接的源端口。)

不保证会使用相同的客户端端口 - 事实上,相同的源端口不能用于相同的源 IP,除非 TCP 连接已经全封闭;这包括TIME_WAIT1 中的那些。由于 TCP 连接完全关闭,源端口将被释放回可用池。

不同的源端口表示存在问题;并且增加的值仅仅是一个实现(和可用的池)细节。另一方面,从不关闭的连接可能是个问题。使用netstat 命令查看 TCP 连接及其状态。


1在具有过多从同一远程 IP 快速创建连接的系统上,可能需要启用 'port reuse'。

"Coping with the TCP TIME-WAIT state on busy Linux servers" 文章值得一读;它包括漂亮的图表、良好的解释和对实际限制的讨论。

【讨论】:

感谢您的解释。我使用 netstat 看了一下,我看到了几分钟获得的端口(当时它们是“TIME_WAIT”),然后它们被释放了。我担心的是我希望使用 POST 以快速(100 毫秒)更新网页上的绘图。我担心这样做我会吃掉一吨的港口。有没有办法强制使用单个端口,或者几秒钟后关闭客户端的 TCP 连接? @radian 通常只有在短时间内处理来自同一源 IP 的 [成千上万] 个请求时才会出现问题。 TCP 连接详细信息本身由网络/驱动程序控制并自动“关闭”(可以使用各种设置,以及强制重用)-此外,发现这个有趣的阅读 vincent.bernat.im/en/blog/2014-tcp-time-wait-state-linux.html(图片很方便) @radian 话虽如此,您可能对“长轮询”、COMET 或 WebSockets 感兴趣,以替代创建 600 个连接/分钟(尤其是当有多个人试图做同样的事情时!) :【参考方案2】:

好吧,我相信你没有做错任何事。 只是你误解了self.client_address中的值

self.client_address 中的端口不是您服务器上的端口,而是用户机器上用于与 Web 服务器通信的端口。

您还可以在此处查看有关端口的一些有用信息: (请检查标记为[正确答案]的答案)

How do multiple clients connect simultaneously to one port, say 80, on a server?

【讨论】:

以上是关于XMLHttpRequest 创建几个传出端口 - 为啥?的主要内容,如果未能解决你的问题,请参考以下文章

我可以在与从该端口加载的脚本文件不同的端口上使用 XMLHttpRequest 吗?

XMLHttpRequest对象有几个返回状态值?Servlet与JSP的关系

Cors XmlHttpRequest 和响应

如何使用Docker容器建立TCP传出连接?

XMLHttpRequest 无法使用 jQuery 加载 URL

MongoDB Chapter1:Introduction