Skip to content

Commit 8ae5fb7

Browse files
committed
Allow OS assign a free port using zero port number as default.
Now servers can be simply created using #new without port number
1 parent 3edd155 commit 8ae5fb7

File tree

5 files changed

+68
-10
lines changed

5 files changed

+68
-10
lines changed

.project

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
'srcDirectory' : ''
3+
}

TCPServer-Tests/TCPServerTestCase.class.st

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ TCPServerTestCase >> setUp [
4545

4646
clientSockets := OrderedCollection new.
4747

48-
server := self serverClass on: 40422
48+
server := self serverClass new
4949
]
5050

5151
{ #category : #running }

TCPServer-Tests/TCPServerTests.class.st

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,23 @@ TCPServerTests >> testHasProcessingPriorityByDefault [
6464
self assert: baseServer processingPriority equals: Processor highIOPriority
6565
]
6666

67+
{ #category : #tests }
68+
TCPServerTests >> testHasSelfAssignedZeroPortByDefault [
69+
70+
self assert: server port equals: 0
71+
]
72+
73+
{ #category : #tests }
74+
TCPServerTests >> testStartingServerOnGivenPortShouldUseIt [
75+
76+
| requiredPort |
77+
requiredPort := 40522 + 32 atRandom.
78+
server port: requiredPort.
79+
server start.
80+
81+
self assert: server port equals: requiredPort
82+
]
83+
6784
{ #category : #tests }
6885
TCPServerTests >> testStartingServerOnPortWhichIsAlreadyInUse [
6986

@@ -87,6 +104,16 @@ TCPServerTests >> testStartingServerShouldAddItToRunningList [
87104
self assert: (TCPServer runningServers includes: server)
88105
]
89106

107+
{ #category : #tests }
108+
TCPServerTests >> testStartingServerShouldAssignRetrievedPort [
109+
110+
self assert: server port equals: 0.
111+
112+
server start.
113+
114+
self assert: server port > 0
115+
]
116+
90117
{ #category : #tests }
91118
TCPServerTests >> testStartingServerTwiceShouldNotCorruptServer [
92119

TCPServer/TCPPharoNetworkLibrary.class.st

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ TCPPharoNetworkLibrary class >> newListenerSocketOn: port [
2626

2727
socket isValid
2828
ifFalse: [ self error: 'Cannot create socket on port ' , port asString ].
29-
socket localPort = port ifFalse: [
29+
port ~= 0 & (socket localPort ~= port) ifTrue: [
3030
socket close; destroy.
3131
self error: 'Port ' , port asString, ' is busy. Try use another port'].
3232

TCPServer/TCPServer.class.st

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,37 @@
11
"
22
I am most primitive TCP server. I implement classic incoming connections loop. My subclasses should implement #processNewConnection: .
33
4-
I am created by #on: message with port number as argument. Then you should call #start to run listener socket and incoming connections loop.
5-
I have list of running servers on class side.
6-
#stop message will close listener socket and terminate incoming connections process.
4+
To start a server simply create an instance and ask it to #start:
75
8-
I delegate sockets creation to TCPNetworkLibrary implementation. It provides simple hook to set up different socket libraries (like Ocean).
6+
server := TCPServerSubclass new.
7+
server start.
8+
9+
It will run listener socket and incoming connections loop.
10+
11+
By default I allow OS to assign free port for me (using zero port number):
12+
13+
server := TCPServerSubclass new.
14+
server port. ""==> 0""
15+
server start.
16+
server port > 0 ""==> true""
17+
18+
But users can specify concrete port using #on: message:
19+
20+
server := TCPServerSubclass on: 40422
21+
22+
If given port is busy the #start message will signal an error.
23+
24+
To stop the server use #stop message:
25+
26+
server stop.
27+
28+
It will close listener socket and terminate incoming connections loop.
29+
30+
I maintain the list of all running servers on my class side variable #RunningServers.
31+
32+
Implementation details
33+
34+
I delegate sockets creation to TCPNetworkLibrary implementation. It provides simple hook to set up different socket libraries (like Ocean) and simplifies testing.
935
1036
Public API and Key Messages
1137
@@ -19,8 +45,8 @@ Internal Representation and Key Implementation Points.
1945
incomingConnectionsProcess: <Process>
2046
listenerSocket: <Socket>
2147
networkLibrary: <TCPNetworkLibrary>
22-
port: <Number>
23-
processingPriority: <Number>
48+
port: <SmallInteger>
49+
processingPriority: <SmallInteger>
2450
2551
"
2652
Class {
@@ -38,7 +64,7 @@ Class {
3864
'AlwaysRestart',
3965
'RunningServers'
4066
],
41-
#category : 'TCPServer'
67+
#category : #TCPServer
4268
}
4369

4470
{ #category : #accessing }
@@ -150,6 +176,7 @@ TCPServer >> incomingConnectionsProcess: anObject [
150176
TCPServer >> initialize [
151177
super initialize.
152178

179+
port := 0. "zero specifies self assigned port for server (assigned by OS)"
153180
networkLibrary := TCPPharoNetworkLibrary.
154181
processingPriority := Processor highIOPriority.
155182
listeningTimeout := 10 seconds
@@ -158,7 +185,8 @@ TCPServer >> initialize [
158185
{ #category : #private }
159186
TCPServer >> initializeListenerSocket [
160187

161-
listenerSocket := networkLibrary newListenerSocketOn: port
188+
listenerSocket := networkLibrary newListenerSocketOn: port.
189+
port := listenerSocket port
162190
]
163191

164192
{ #category : #testing }

0 commit comments

Comments
 (0)