Show More
@@ -20,6 +20,7 b' Authors:' | |||||
20 | import errno |
|
20 | import errno | |
21 | import logging |
|
21 | import logging | |
22 | import os |
|
22 | import os | |
|
23 | import random | |||
23 | import re |
|
24 | import re | |
24 | import select |
|
25 | import select | |
25 | import signal |
|
26 | import signal | |
@@ -97,6 +98,17 b' def url_path_join(a,b):' | |||||
97 | else: |
|
98 | else: | |
98 | return a+b |
|
99 | return a+b | |
99 |
|
100 | |||
|
101 | def random_ports(port, n): | |||
|
102 | """Generate a list of n random ports near the given port. | |||
|
103 | ||||
|
104 | The first 5 ports will be sequential, and the remaining n-5 will be | |||
|
105 | randomly selected in the range [port-2*n, port+2*n]. | |||
|
106 | """ | |||
|
107 | for i in range(min(5, n)): | |||
|
108 | yield port + i | |||
|
109 | for i in range(n-5): | |||
|
110 | yield port + random.randint(-2*n, 2*n) | |||
|
111 | ||||
100 | #----------------------------------------------------------------------------- |
|
112 | #----------------------------------------------------------------------------- | |
101 | # The Tornado web application |
|
113 | # The Tornado web application | |
102 | #----------------------------------------------------------------------------- |
|
114 | #----------------------------------------------------------------------------- | |
@@ -212,6 +224,7 b' aliases = dict(ipkernel_aliases)' | |||||
212 | aliases.update({ |
|
224 | aliases.update({ | |
213 | 'ip': 'NotebookApp.ip', |
|
225 | 'ip': 'NotebookApp.ip', | |
214 | 'port': 'NotebookApp.port', |
|
226 | 'port': 'NotebookApp.port', | |
|
227 | 'port-retries': 'NotebookApp.port_retries', | |||
215 | 'keyfile': 'NotebookApp.keyfile', |
|
228 | 'keyfile': 'NotebookApp.keyfile', | |
216 | 'certfile': 'NotebookApp.certfile', |
|
229 | 'certfile': 'NotebookApp.certfile', | |
217 | 'notebook-dir': 'NotebookManager.notebook_dir', |
|
230 | 'notebook-dir': 'NotebookManager.notebook_dir', | |
@@ -222,7 +235,7 b' aliases.update({' | |||||
222 | # multi-kernel evironment: |
|
235 | # multi-kernel evironment: | |
223 | aliases.pop('f', None) |
|
236 | aliases.pop('f', None) | |
224 |
|
237 | |||
225 | notebook_aliases = [u'port', u'ip', u'keyfile', u'certfile', |
|
238 | notebook_aliases = [u'port', u'port-retries', u'ip', u'keyfile', u'certfile', | |
226 | u'notebook-dir'] |
|
239 | u'notebook-dir'] | |
227 |
|
240 | |||
228 | #----------------------------------------------------------------------------- |
|
241 | #----------------------------------------------------------------------------- | |
@@ -272,6 +285,9 b' class NotebookApp(BaseIPythonApplication):' | |||||
272 | port = Integer(8888, config=True, |
|
285 | port = Integer(8888, config=True, | |
273 | help="The port the notebook server will listen on." |
|
286 | help="The port the notebook server will listen on." | |
274 | ) |
|
287 | ) | |
|
288 | port_retries = Integer(50, config=True, | |||
|
289 | help="The number of additional ports to try if the specified port is not available." | |||
|
290 | ) | |||
275 |
|
291 | |||
276 | certfile = Unicode(u'', config=True, |
|
292 | certfile = Unicode(u'', config=True, | |
277 | help="""The full path to an SSL/TLS certificate file.""" |
|
293 | help="""The full path to an SSL/TLS certificate file.""" | |
@@ -422,10 +438,8 b' class NotebookApp(BaseIPythonApplication):' | |||||
422 | 'but not using any encryption or authentication. This is highly ' |
|
438 | 'but not using any encryption or authentication. This is highly ' | |
423 | 'insecure and not recommended.') |
|
439 | 'insecure and not recommended.') | |
424 |
|
440 | |||
425 | # Try random ports centered around the default. |
|
441 | success = None | |
426 | from random import randint |
|
442 | for port in random_ports(self.port, self.port_retries+1): | |
427 | n = 50 # Max number of attempts, keep reasonably large. |
|
|||
428 | for port in range(self.port, self.port+5) + [self.port + randint(-2*n, 2*n) for i in range(n-5)]: |
|
|||
429 | try: |
|
443 | try: | |
430 | self.http_server.listen(port, self.ip) |
|
444 | self.http_server.listen(port, self.ip) | |
431 | except socket.error, e: |
|
445 | except socket.error, e: | |
@@ -434,7 +448,12 b' class NotebookApp(BaseIPythonApplication):' | |||||
434 | self.log.info('The port %i is already in use, trying another random port.' % port) |
|
448 | self.log.info('The port %i is already in use, trying another random port.' % port) | |
435 | else: |
|
449 | else: | |
436 | self.port = port |
|
450 | self.port = port | |
|
451 | success = True | |||
437 | break |
|
452 | break | |
|
453 | if not success: | |||
|
454 | self.log.critical('ERROR: the notebook server could not be started because ' | |||
|
455 | 'no available port could be found.') | |||
|
456 | raise RuntimeError | |||
438 |
|
457 | |||
439 | def init_signal(self): |
|
458 | def init_signal(self): | |
440 | # FIXME: remove this check when pyzmq dependency is >= 2.1.11 |
|
459 | # FIXME: remove this check when pyzmq dependency is >= 2.1.11 |
General Comments 0
You need to be logged in to leave comments.
Login now