Why doesn't the second listen fail? And is there a way to fail if a port is already in use? socket := Socket newTCP. socket listenOn: 8088. socket2 := Socket newTCP. socket2 listenOn: 8088. (socket isValid and: [ socket2 isValid ]) ifTrue: [ self error: 'how can I be listening twice on the same port?!' ]. socket destroy. socket2 destroy -- View this message in context: http://forum.world.st/Listening-on-sockets-tp4618129.html Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
On 08 May 2012, at 19:24, Sean P. DeNigris wrote:
Why doesn't the second listen fail? And is there a way to fail if a port is already in use?
socket := Socket newTCP. socket listenOn: 8088.
socket2 := Socket newTCP. socket2 listenOn: 8088.
(socket isValid and: [ socket2 isValid ]) ifTrue: [ self error: 'how can I be listening twice on the same port?!' ].
socket destroy. socket2 destroy
Welcome to the strange world of Sockets, Sean ;-) I have this test in Zn: ZnSingleThreadedServer>>isListening "Return true when I have a valid server socket listening at the correct port" ^ self serverSocket notNil and: [ self serverSocket isValid and: [ self serverSocket localPort = self port ] ] You can try, maybe it solves your 'problem'. Sven -- Sven Van Caekenberghe http://stfx.eu Smalltalk is the Red Pill
Sven Van Caekenberghe wrote
You can try, maybe it solves your 'problem'.
Thanks, Sven! It works, but not for ip6. I guess this is more complicated than I thought. OS X lets me listen on a port that's already listening with ip6. before I open my port, lsof shows: java ... IPv6 ... TCP *:port_number (LISTEN) and after: java ... IPv6 ... TCP *:port_number (LISTEN) CogVM ... IPv4 ... TCP *:same_port_number!!! (LISTEN) WTF! For now, I'm using the ugly and non-portable: | lsof output p portsInUse | lsof := PipeableOSProcess waitForCommand: 'lsof -i -P -FnT'. output := p output. portsInUse := Set new. "Output is e.g. 'n*:52844TST=LISTENTQR=0TQS=0', where there is an lf between each field i.e. between the 4 at the end of the example's port number and the T, which starts the status info, and the next address" "So we're matching the colon before the port number, the number, lf (now we're in the status info), and then LISTEN before the next lf (when the next address begins)" output regex: '\:[[:digit:]]+\s\S*LISTEN' matchesDo: [ :e | portsInUse add: e allButFirst asNumber ]. isAvailable := (portsInUse includes: my_port) not. but it seems like it'd be nice to have a portable way, since it's generally useful, e.g. in zinc's tests, if I open port 1700 and run the server tests, they fail intermittently. With an appropriate comment to the ip6 limitation, I think this would be very useful: "Would this go in ZnNetworkingUtils? ZnUtils?" isPortAvailable: aNumber "Does not take ip6 into account i.e. if the port is already open with ip6, will indicate it is available" | socket isAvailable | socket := Socket newTCP listenOn: aNumber. isAvailable := socket isValid and: [ socket localPort = aNumber ]. socket destroy. ^ isAvailable. then the server tests could be more robust... ZnServerTests>>port ^ (1700 to: 1750) detect: [ :e | ZnNetworkingUtils isPortAvailable: e ]. and here's a test for the new functionality... testIsPortAvailable | availablePort utils socket | utils := ZnNetworkingUtils default. availablePort := (1700 to: 1800) detect: [ :e | utils isPortAvailable: e ]. socket := Socket newTCP listenOn: availablePort. self deny: (utils isPortAvailable: availablePort). socket destroy. self assert: (utils isPortAvailable: availablePort). -- View this message in context: http://forum.world.st/Listening-on-sockets-tp4618129p4618367.html Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
Thanks for the code, Sean, I will consider it. Now, the tests can indeed 'fail' but on the explicitely tested condition that they are 'running alone on that port'. It is not really a failure, more a 'resource not available'. The difference between the current approach and what you propose is like the difference between optimistic and pessimistic locking. And even in your solution there might be a very small time window were things still do wrong. As for the actual functionality of the socket plugin code, let's say it could be modernized. Sven On 08 May 2012, at 21:01, Sean P. DeNigris wrote:
Sven Van Caekenberghe wrote
You can try, maybe it solves your 'problem'.
Thanks, Sven!
It works, but not for ip6. I guess this is more complicated than I thought. OS X lets me listen on a port that's already listening with ip6.
before I open my port, lsof shows: java ... IPv6 ... TCP *:port_number (LISTEN)
and after: java ... IPv6 ... TCP *:port_number (LISTEN) CogVM ... IPv4 ... TCP *:same_port_number!!! (LISTEN)
WTF!
For now, I'm using the ugly and non-portable: | lsof output p portsInUse | lsof := PipeableOSProcess waitForCommand: 'lsof -i -P -FnT'. output := p output. portsInUse := Set new. "Output is e.g. 'n*:52844TST=LISTENTQR=0TQS=0', where there is an lf between each field i.e. between the 4 at the end of the example's port number and the T, which starts the status info, and the next address" "So we're matching the colon before the port number, the number, lf (now we're in the status info), and then LISTEN before the next lf (when the next address begins)" output regex: '\:[[:digit:]]+\s\S*LISTEN' matchesDo: [ :e | portsInUse add: e allButFirst asNumber ]. isAvailable := (portsInUse includes: my_port) not.
but it seems like it'd be nice to have a portable way, since it's generally useful, e.g. in zinc's tests, if I open port 1700 and run the server tests, they fail intermittently. With an appropriate comment to the ip6 limitation, I think this would be very useful:
"Would this go in ZnNetworkingUtils? ZnUtils?" isPortAvailable: aNumber "Does not take ip6 into account i.e. if the port is already open with ip6, will indicate it is available"
| socket isAvailable | socket := Socket newTCP listenOn: aNumber. isAvailable := socket isValid and: [ socket localPort = aNumber ]. socket destroy. ^ isAvailable.
then the server tests could be more robust... ZnServerTests>>port ^ (1700 to: 1750) detect: [ :e | ZnNetworkingUtils isPortAvailable: e ].
and here's a test for the new functionality... testIsPortAvailable
| availablePort utils socket | utils := ZnNetworkingUtils default. availablePort := (1700 to: 1800) detect: [ :e | utils isPortAvailable: e ].
socket := Socket newTCP listenOn: availablePort. self deny: (utils isPortAvailable: availablePort).
socket destroy. self assert: (utils isPortAvailable: availablePort).
-- View this message in context: http://forum.world.st/Listening-on-sockets-tp4618129p4618367.html Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
On 08/05/2012 20:01, Sean P. DeNigris wrote:
It works, but not for ip6. I guess this is more complicated than I thought. OS X lets me listen on a port that's already listening with ip6.
before I open my port, lsof shows: java ... IPv6 ... TCP *:port_number (LISTEN)
and after: java ... IPv6 ... TCP *:port_number (LISTEN) CogVM ... IPv4 ... TCP *:same_port_number!!! (LISTEN)
WTF!
Hmm, aren't IPv4 and IPv6 ports completely separate namespaces?
participants (3)
-
Douglas Brebner -
Sean P. DeNigris -
Sven Van Caekenberghe