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
|