Home   Archive   Permalink



Don't understand ports at all

I am trying to understand how tcp ports work so I can make myself a little helper program on one of our office servers and send messages to the helper program from my desktop computer. I believe that tcp ports are the way to do that, and I have found two little demo programs on the internet (a server program and a client program) that I am trying to use to learn how to do this client-server communication. Naturally, they don't work, and I am hindered in my efforts by trying to map the REBOL syntax to what I expect this server program to do. I expect it to wait for a message, process that message, and then go back to waiting. I do see some of that, but I see other stuff as well, and it all makes no sense.
    
Here is the client program that sends one message to the server and quits:
R E B O L [
]
    
;; [---------------------------------------------------------------------------]
;; [ Client program. Sends messages to the server.                            ]
;; [---------------------------------------------------------------------------]
    
;; -- Set up a "port" for outgoing messages.
CONNECTION-OUT: open/direct/lines/no-wait tcp://10.1.0.12:14000
    
;; -- Get some text for a one-time outgoing message.
OUTGOING-MESSAGE: ask "enter some text to send: "
    
;; -- Send the message to the server.
insert CONNECTION-OUT OUTGOING-MESSAGE
    
;; -- Wait for an answer and print what we get, as-is.
;; -- Does not work at this time.
;;print "waiting for reply"
;;wait CONNECTION-OUT
;;print copy CONNECTION-OUT
    
;; -- Close the port.
close CONNECTION-OUT
    
;; -- Halt for debugging, so we probe around if necessary.
halt
    
Here is the server program that waits for messages. I put in some displays to try to see just where it is not working:
R E B O L [
]
    
;; [---------------------------------------------------------------------------]
;; [ Server program. Waits for tcp messages.                                 ]
;; [---------------------------------------------------------------------------]
    
print "Opening port"
LISTEN-PORT: open/direct/lines/no-wait tcp://:14000
    
print "Waiting for port to open"
wait LISTEN-PORT
    
print "Creating connection to port"
CONNECTION-IN: first LISTEN-PORT
    
;; for debugging
HALT-COUNTER: 0
    
print "Starting to wait for messages"
forever [
     print "Waiting for one message"
     HALT-COUNTER: HALT-COUNTER + 1
     if (HALT-COUNTER > 10) [halt]    
     wait CONNECTION-IN
     print "Looping through whatever we get from the port"
     foreach INCOMING-MESSAGE any [copy CONNECTION-IN []] [
         print INCOMING-MESSAGE
     ]
]
    
print "Closing port"
close LISTEN-PORT
    
And there is what the server program does:
>> do %tcpserver.r
Opening port
Waiting for port to open
Creating connection to port
Starting to wait for messages
Waiting for one message
Looping through whatever we get from the port
Text from client program
Waiting for one message
Looping through whatever we get from the port
Waiting for one message
Looping through whatever we get from the port
Waiting for one message
Looping through whatever we get from the port
Waiting for one message
Looping through whatever we get from the port
Waiting for one message
Looping through whatever we get from the port
Waiting for one message
Looping through whatever we get from the port
Waiting for one message
Looping through whatever we get from the port
Waiting for one message
Looping through whatever we get from the port
Waiting for one message
Looping through whatever we get from the port
Waiting for one message
>>
    
When I run the server program, it displays the messages...
Opening port
Waiting for port to open
    
...and then sits there. Then I entered the text...
Text from the client program
    
...and THEN it displayed:
Starting to wait for messages
Waiting for one message
Looping through whatever we get from the port
Text from the client program
    
...and then it went into the loop for "waiting for one message."    
Without the debugging counter, the server program runs until it uses up all the memory it can and is terminated.
    
This is a lengthy question, but it boils down to, how can I make a server program that waits for a message, processes that message, then goes back to waiting for another message?
    
Thank you.
    


posted by:   Steven White       28-Nov-2014/15:17:57-8:00



One perhaps-less-appreciated feature of such a forum is that by going through the effort of framing a question, one sometimes answers it. I don't know if I have answered it, but I found another article by Carl that gave me another view of this port business. In my new paradigm, a port is the logical mechanism by which messages come in, and a connection is what one must make, through the port, to receive a message. In other words, you open a port, and then you open a connection and wait for something to connect on the other end. When something connects from the other end, you then wait for data to appear and copy stuff out of the connection until there is nothing left, close the connection, then create a NEW connection and wait for something to come in over that new connection. With that new paradigm in my head, the server script becomes this: (which does work as I want)
    
R E B O L [
]
    
;; [---------------------------------------------------------------------------]
;; [ Server program. Waits for tcp messages.                                 ]
;; [---------------------------------------------------------------------------]
    
INCOMING-MESSAGE: ""
    
print "Opening port"
LISTEN-PORT: open/lines tcp://:14000
    
print "Beginning message wait loop"
forever [
     print "Creating connection to port"
     CONNECTION-IN: first LISTEN-PORT
     print "Waiting for one message"
     wait CONNECTION-IN
     print "Saving the message we get from the port"
     INCOMING-MESSAGE: copy ""
     foreach INPUT-LINE any [copy CONNECTION-IN []] [
         INCOMING-MESSAGE: INPUT-LINE
         print INCOMING-MESSAGE
     ]
     close CONNECTION-IN
]
    
print "Closing port"
close LISTEN-PORT
    
If anyone wants to refine my understanding, I would be grateful. Otherwise, I do have the result I was looking for. Once one understands what the terminology means, things become clear(er).
    
Thank you.


posted by:   Steven White       28-Nov-2014/16:17:07-8:00



Attempting to build on my success, I have stumped myself again. The following client and server scripts work. They are almost the same as above, but I took out the comments and the displays now that I sort of (but not quite) understand what is going on.
    
Client:
R E B O L [
]
    
;; [---------------------------------------------------------------------------]
;; [ Client program. Sends messages to the server.                            ]
;; [---------------------------------------------------------------------------]
    
REPLY-MESSAGE: ""
    
CONNECTION-OUT: open/direct/lines/no-wait tcp://10.1.0.12:14000
    
OUTGOING-MESSAGE: ask "enter some text to send: "
    
insert CONNECTION-OUT OUTGOING-MESSAGE
    
;; -- Wait for an answer and print what we get, as-is.
;; -- Does not work at this time.
    
;print "waiting for reply"
;wait CONNECTION-OUT             ;; server times out what I uncomment this
;REPLY-MESSAGE: copy CONNECTION-OUT
;print REPLY-MESSAGE
    
close CONNECTION-OUT
    
halt
    
Server:
R E B O L [
]
    
;; [---------------------------------------------------------------------------]
;; [ Server program. Waits for tcp messages.                                 ]
;; [---------------------------------------------------------------------------]
    
INCOMING-MESSAGE: ""
    
PROCESS-INCOMING: does [
     print "Process a message"
     print INCOMING-MESSAGE
;;; insert CONNECTION-IN "OK"    ;; times out when I uncomment this
]
    
LISTEN-PORT: open/lines tcp://:14000
    
forever [
     CONNECTION-IN: first LISTEN-PORT
     wait CONNECTION-IN
     INCOMING-MESSAGE: copy ""
     foreach INPUT-LINE any [copy CONNECTION-IN []] [
         INCOMING-MESSAGE: INPUT-LINE
         PROCESS-INCOMING
     ]
     close CONNECTION-IN
]
    
close LISTEN-PORT
    
What I want to do now is, have the server send back a reply after it is done processing a line of text retrieved from the connection. The programs above work, BUT, if I un-comment the part of the client that waits for a reply, and un-comment the part of the server that sends a reply, the server gets a time-out. Based on my paradigm, I am assuming that any response must be sent back over the connection (if that even can be done) because the connection is what connects the server and the client.    
    
There is one way I CAN get a reply to go back to the client, and that is if I replace the "foreach" line in the server with:
    
     foreach INPUT-LINE first CONNECTION-IN [
    
But what happens when I do that is that the function PROCESS-INCOMING gets executed once for each character in the line of text sent from the client. I suppose I could rebuild the line from the client a character at a time and THEN process it, but I bet there is just something else that I don't understand about using ports, and I am hoping someone can point it out.
    
Thank you.

posted by:   Steven White       28-Nov-2014/17:35:02-8:00



I have tried ports years ago, and they did seem to work. I may have used two instances of REBOL on the same computer - not sure if I went on to trying a client on one computer, the server on another.

posted by:   Matt       30-Nov-2014/14:34:03-8:00



Steve,
    
Take a look at http://re-bol.com/rebol-multi-client-databases.html
    
Here's a basic template from the beginning of that tutorial, which you should be able to extend as needed. Notice all the different labeled items ('port, 'commands, 'data, 'connect, 'results). You can put each of those items on different lines, and do with them what you want:
    
R E B O L [title: "Simple Data Server"]
print "waiting..."
port: open/lines tcp://:55555
forever [
     probe commands: load data: first wait connect: first wait port
     probe result: mold do commands
     insert connect result
     close connect
]
    
Here's the same server code, drawn out to perhaps clarify each step. Notice that each incoming client connection is opened and closed inside the 'forever loop. Data is sent back to the client through that connection, and then the connection is closed:
    
R E B O L [title: "Simple Data Server"]
print "waiting..."
port: open/lines tcp://:55555
forever [
     connect: first wait port
     data: first wait connect
     commands: load data
     probe commands
     result: mold do commands
     probe result
     insert connect result
     close connect
]
    
Notice the arbitrary word labels in this client code too ('serverip (and of course the port number), 'port, 'connect, 'data-response). Notice that data is sent to the server by inserting into the port, and data is received back from the server by opening a connection (waiting on the port). Play with them all to see what they do:
    
R E B O L [title: "Simple Client"]
print "sending..."
serverip: "localhost"
port: open/lines rejoin [tcp:// serverip ":55555"]
insert port {print "Code received, sending the number 1 back to client." 1}
data-response: load first connect: wait port
either 1 = data-response [print "Success"] [print "Failure"]
close connect
close port
halt
    
Be aware that the R3 networking model works differently.

posted by:   Nick       30-Nov-2014/18:00:08-8:00