3

I'm newbie to JavaScript and AJAX here. Also new to web communications in general.

I'm trying to create a dynamically updating webpage that communicates to a Python server. I have been testing everything locally and so far all works.. I think.

The Python server serves "page.html" on localhost port 8000. The HTML page uses AJAX and XMLHttpRequest to POST data to the server. I can send data to the server just fine.

Here's the problem: my server indicates that for each post a new client port is opened. This scares me as I'm used to TCP sockets where communication occurs on a single port.

Here's the server code (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()

Here's the HTML code (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>

Here's the server output after sending 1 to 6 on the page.

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']}

To test launch server.py, then go to a browser and type in

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

As you can see the port increments for each POST. Is there anything I'm doing wrong? I feel like the XHR is lingering and it needs to be closed, but from what I've read online, apparent creating a new XHR is necessary for each POST. Thanks!

2 Answers2

1

That is fine. The server selects a new source port out of its available pool for such ports - this ensures a unique TCP connection tuple for HTTP each request and the corresponding TCP connection it established. (It is the server that chooses the source port it uses for the incoming connection.)

There is no guarantee that the same client port will be used - and indeed the same source port cannot be used for the same source IP unless the TCP connection has been fully closed; this includes those in TIME_WAIT1. As the TCP connections are fully closed the source ports will be released back to the available pool.

A different source port is not indicative of a problem; and an increasing value is merely an implementation (and available pool) detail. Connections that never close, on the other hand, can be a problem. Use the netstat command to view TCP connections and their state.


1 On systems with excessively many quickly created connections from the same remote IP it may be required to enable 'port reuse'.

The "Coping with the TCP TIME-WAIT state on busy Linux servers" article is a good read; it includes pretty diagrams, good explanations, and discussion of practical limits.

Community
  • 1
  • 1
user2864740
  • 60,010
  • 15
  • 145
  • 220
  • Thanks for the explanation. I had a look using netstat and I saw the ports acquired for a couple minutes (at which they were "TIME_WAIT"), then they were released. My concern is that I was hoping to use POST to update a plot on a webpage at a fast rate (100 ms). I'm concerned that I'm going to be eating a tonne of ports doing this. Is there a way to force a single port, or close the TCP connection on the client-side after a few seconds? –  Sep 14 '15 at 00:09
  • @radian There will generally only be a problem if handling *[tens of] thousands* of requests from the same source IP in a short duration. The TCP connection details itself are controlled by the network/driver and is 'closed' automatically (there are various settings that can be employed, as well as forcing reuse) - also, found this interesting read http://vincent.bernat.im/en/blog/2014-tcp-time-wait-state-linux.html (the pictures are handy) – user2864740 Sep 14 '15 at 00:10
  • @radian That being said, you may be interested in 'long polling', COMET, or WebSockets as an alternative to creating 600 connections/minute (especially when there are multiple people trying to do the same thing!) :} – user2864740 Sep 14 '15 at 00:16
0

Well, you do not do anything wrong I believe. Just you misunderstood the value in self.client_address

The port in self.client_address is not a port on your server, but port being used on the user's machine to communicate with the web server.

Also you can check some helpful information regarding the port here: (Please check the answer marked as the [Right Answer])

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

Community
  • 1
  • 1
Codemole
  • 3,069
  • 5
  • 25
  • 41