[1/10] from: patrick::philipot::laposte::net at: 15-Aug-2003 19:18
Hi List I am still struggling to build a Rebol Client for dbtcp. (dbtcp is a server for ODBC databases). I am able to send dbtcp my requests, but I am not able to receive anything from it. I know it is receiving the requests because I am using a tcp-sniffer (tcpview for windows). There is my Rebol code:
>> serv: open/binary tcp://localhost:3000 >> insert serv "^(05)^(00)^(0A)^(00)^(00)^(01)DSN=mytest;" >> insert serv "^(05)^(00)^(17)^(00)^(00)^(02)SELECT * from mytable^(0D)^(0A)" >> insert serv "^(05)^(00)^(0B)^(00)^(00)^(06)FetchRecord" >> copy serv
** Access Error: Network timeout ** Near: copy serv
>> close serv
The line with "copy serv" is meant to read whatever the server is sending. I have tried to use it after each 'insert with the same result. There is the output from tcpview: Local Port (3000) opened Waiting for connections 156: Client connected; 127.0.0.1:1213 156: Connecting to Server 156: Connected to Server 156: Client to Server (17 bytes) 0000 05 00 0A 00 00 01 44 53 4E 3D 6D 79 74 65 73 74 ......DSN=mytest 0010 3B ; 156: Server to Client (18 bytes) 0000 05 00 0C 01 01 33 44 53 4E 3D 6D 79 74 65 73 74 .....3DSN=mytest 0010 0D 0A .. 156: Client to Server (29 bytes) 0000 05 00 17 00 00 02 53 45 4C 45 43 54 20 2A 20 66 ......SELECT * f 0010 72 6F 6D 20 6D 79 74 61 62 6C 65 0D 0A rom mytable.. 156: Server to Client (29 bytes) 0000 05 00 17 01 01 33 53 45 4C 45 43 54 20 2A 20 66 .....3SELECT * f 0010 72 6F 6D 20 6D 79 74 61 62 6C 65 0D 0A rom mytable.. 156: Client to Server (17 bytes) 0000 05 00 0B 00 00 06 46 65 74 63 68 52 65 63 6F 72 ......FetchRecor 0010 64 d 156: Server to Client (21 bytes) 0000 05 00 0F 01 01 36 00 05 48 61 72 72 79 00 06 50 .....6..Harry..P 0010 6F 74 74 65 72 otter 156: Client disconnected 156: Disconnected from Server It is clear that dbtcp is sending data (line like 156: Server to Client (21 bytes)). Furthermore, when using the dbtcp-client-test provided with dbtcp, I can see the client receiving this exact data. Something else is troubling me. It is "1213" in the line: 156: Client connected; 127.0.0.1:1213 (the number is always different for each connection). If i use probe serv, I can see it again:
>> probe serv
make object! [ scheme: 'tcp host: "localhost" port-id: 3000 user: none pass: none target: none path: none proxy: none access: none allow: none buffer-size: none limit: none handler: none status: none size: none date: none url: none sub-port: none locals: none state: make object! [ flags: 524835 misc: [124  0] tail: 0 num: 0 with: "^M^/" custom: none index: 0 func: 3 fpos: 0 inBuffer: none outBuffer: none ] timeout: none local-ip: 127.0.0.1 local-service: none remote-service: none last-remote-service: none direction: none key: none strength: none algorithm: none block-chaining: none init-vector: none padding: none async-modes: none remote-ip: 127.0.0.1 local-port: 1213 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< here remote-port: 3000 backlog: none device: none speed: none data-bits: none parity: none stop-bits: none rts-cts: true user-data: none awake: none ] My guess is that I should use this number in some way. But I have looked everywhere for an example without success. Does anybody have a clue? Regards Patrick The journey is the reward. ~ Chinese Proverb
[2/10] from: Rebolinth:nodep:dds:nl at: 15-Aug-2003 19:39
-- Conversation/lunch: "How do you Eat your Rebol in the Morning?" Quoting patrick Hello Patrick, Here some tips programming servers under rebol, maybe usefull i dont know, but what i know is dat i had to rethink the rebol logic befor i was able to program servers in rebol...but finaly its easy ;-) Make sure what yuo want with your server when opening it: ie. lines based? binary based? blocking or non-blocking? (no-wait) direct? (which is default) Then when you setup a server under rebol like: server: open tcp://:listenport the server will listen on ALL nic's on your machine so the connection coming in could be on ANY ip address on that NIC. the server 'port is now opened and is ready to read incoming sessions, BUT when yuo have a tcp server make a selection to distinguish between the SERVER itself and or a NEW connection. that looks like this: connection: wait server ;; this wait for events on the server 'port when a session comes INto server the 'connection will be SERVER-PORT itself !!! (Depends if yuo have it all inside a forever loop with a wait inside!! because then you might split it with a "either equal? server conenction [yes then][ no then] or use dispatch or port/awake) do a "first" on "connection" and you will get the 'port information from the new remote-client!! like -> client: first connection This client 'port has information like client/remote-ip client/remote-port client/local-ip client/local-port and ie. client/state/flags Now you can read or write to THAT specific client, Still !! If client: first connection you can do read-io write-io on the client-server or insert copy anyting with block related ... STILL keep in mind, that tracking a remote-port disconnect is not possible in rebol, you can only check if the remote hung up by doing am action like insert, first copy on the client port befor you know its closed (irritating..) Anyway.. here my MULTI SESSION ECHHO SERVER ... enjoy, Norman. rebol [ author: "rebolinth nodep dds nl" version: "1.0" ] ports:  ; ports we listen on clients:  ; ip:port dbase listener: open/lines/direct tcp://:2000 ports: reduce [ 0:01 listener ] forever [ ;;; wait for 0:01 or ports event, use timer to prevent deadlocks, dispatch ;;; is an option perhpas here, or even WAIT awake port: wait ports if port [ either port = listener [ append ports new: first port print rejoin [ now " [NEW] " new/remote-ip ":" new/remote-port ] append/only clients rejoin [ new/remote-ip ":" new/remote-port ] insert new rejoin [ "Welcome " new/remote-ip ":" new/remote-port ] ][ ;;; try to read a line from the port, if error? then client is gone either error? try [ line: first port ] [ find clients rejoin [ port/remote-ip ":" port/remote-port ] print rejoin [ now " [DIS] " port/remote-ip ":" port/remote-port ] remove find ports port remove find clients rejoin [ port/remote-ip ":" port/remote-port ] ][ print rejoin [ now " [INC] " port/remote-ip ":" port/remote-port " > " line ] ;;; send all ports, because we read a line from one, to all foreach x next next ports [ insert x line ] ] ] ] ] close listener
[3/10] from: Rebolinth:nodep:dds:nl at: 15-Aug-2003 19:45
-- Conversation/lunch: "How do you Eat your Rebol in the Morning?" Quoting patrick ..Hehe oo yes..forgot.. client/remote-ip remote address it connects to client/remote-port remote port is connects to client/local-ip local ip it connects from client/local-port local port it connects from (R)egards, Norman
[4/10] from: patrick:philipot:laposte at: 15-Aug-2003 21:29
Hi Norman, Thank you for this quick answer. You are giving me a fine Rebol server however I was looking more for a Rebol client. I will re-read your code again of course because I do not understand everything. For example, I had never seen 'wait used like this before: port: wait ports I wonder now if dbtcp is a special case... But the fact that tcpview can intercept the traffic is a proof that it is regular server isn't it? It woulds have been a lot more easier if I could have got a Rebol tcp sniffer instead of tcpview... So still looking for help ... Regards Patrick
[5/10] from: Rebolinth:nodep:dds:nl at: 15-Aug-2003 22:50
Quoting patrick <[patrick--philipot--laposte--net]>: Hello Patrick, Well yes basicly i gave you a server to understand the working of the client ;-) Never the less Rebol tcp client connections work the same way..only different...hehe Basicly the idea behind the 'ports under rebol is very nice, because a file a serial a tcp an udp a console a sound a crypting they are all ports .... Coming back to your server connection, If you know how the data is sent from the server to you client (line based or raw binary?) you should change the behaviour of your client on this... this sets your network timeout on the revceive or send over network ports... system/options/schemes/timeout: 60 (default its 30 seconds) The best thing to make a client is that, for very write action you should also read (because you probably will receive data after writing?) or reverse... here an exmaple: b: open/direct/binary/no-wait tcp://localhost:21 print copy b the print copy b will return for you the data from the port putting the above in a loop with your data to send and the expected result to read should make a nice client... Try it...dont forget to read the online docs.. takes some minutes to understand but then you have someting nice ;-) Dont forget to peek in the library section too.. (R)egards, Norman.
[6/10] from: patrick:philipot:laposte at: 15-Aug-2003 23:50
Hello Norman, Thank you again but your client is basically what I have done in the first place. The big problem being that 'copy never gave me any data. No matter where I put it.
>> serv: open/binary tcp://localhost:3000 >> insert serv "^(05)^(00)^(0A)^(00)^(00)^(01)DSN=mytest;" >> insert serv "^(05)^(00)^(17)^(00)^(00)^(02)SELECT * from
>> insert serv "^(05)^(00)^(0B)^(00)^(00)^(06)FetchRecord" >> copy serv
** Access Error: Network timeout ** Near: copy serv
>> close serv
I'am still thinking that dbtcp deserves a special coding. Regards Patrick
[7/10] from: g:santilli:tiscalinet:it at: 16-Aug-2003 0:50
Hi Patrick, On Friday, August 15, 2003, 11:50:45 PM, you wrote: p> I'am still thinking that dbtcp deserves a special coding. Actually, I think you just need to open your port as /NO-WAIT. Otherwise, COPY waits for the other end to close the port before returning. Regards, Gabriele. -- Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer Amiga Group Italia sez. L'Aquila --- SOON: http://www.rebol.it/
[8/10] from: maarten:vrijheid at: 16-Aug-2003 7:46
OK, see below for some explanations.
> -----Original Message----- > > There is my Rebol code: > > >> serv: open/binary tcp://localhost:3000
Change this to open/binary/no-wait
> >> insert serv "^(05)^(00)^(0A)^(00)^(00)^(01)DSN=mytest;" > >> insert serv "^(05)^(00)^(17)^(00)^(00)^(02)SELECT * from > mytable^(0D)^(0A)" > >> insert serv "^(05)^(00)^(0B)^(00)^(00)^(06)FetchRecord" > >> copy serv
copy will now return either an empty binary/string or what's available. So you'll need to do something like: Buff: make binary! 2048 Until [ wait serv data: copy serv if not empty? Data [ append buff data] finished-reading buff ] with finished-reading a function that checks to see if you have got all data. This for example how the old Rugby does these things.
> >> close serv > My guess is that I should use this number in some way. > But I have looked everywhere for an example without success.
No, that's just some info you can forget. It is the number that is assigned to the connection by the OS, but you are handed back (and are only interested in).... the connection itself. --Maarten
[9/10] from: maarten:vrijheid at: 16-Aug-2003 7:51
> For example, I had never seen 'wait used like this before: > port: wait ports >
You can wait on a block of ports and get the port that has an event back: Wait [ ... ] Or with a timeout: Wait [ ... 0:0:1] Which returns none (tomeout) or the port But the best is: Wait/all [ ... timeout ] This will return none with a timeout and a block of all ports that have an event. This is a bit more efficient than entering the event loop again and again. --Maarten
[10/10] from: patrick:philipot:laposte at: 16-Aug-2003 12:28
Hi Maarten, Gabriele, and Norman Thanks to you, it works now. I needed the open/no-wait ! So now, I am trying to put all this in a 'scheme. It works pretty well but for the no-wait part. The scheme is very short: make root-protocol [ scheme: 'dbtcp port-id: 3000 port-flags: system/standard/port-flags/pass-thru open-check: none open: func [port [port!] /local connection-string][ open-proto port port/sub-port/state/flags: 524835 ; force /direct/binary mode connection-string: system/words/copy ^(05)^(00)^(0A)^(00)^(00)^(01) if not none? port/target [ append connection-string join "DSN=" port/target ";" ] ] if not none? port/user [ append connection-string join "UID=" port/user ";" ] ] if not none? port/pass [ append connection-string join "PWD=" port/pass ";" ] ] insert port connection-string ] insert: function [ port data ] [ ] [ system/words/insert port/sub-port data ] copy: func [ port ] [ make string! system/words/copy port/sub-port ] net-utils/net-install dbtcp self 3000 ] The test program is very short too. Rebol trace/net on do %dbtcp-scheme.r db: open dbtcp://localhost/mytest insert db rejoin ["^(05)^(00)^(17)^(00)^(00)^(02)" "select * from mytable" ^(0D)^(0A) ] insert db "^(05)^(00)^(0B)^(00)^(00)^(06)FetchRecord" print mold copy db ; <<<<<<<<<<<<<< TIMEOUT ERROR !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! close db I can tell that all this work pretty well because tcpview shows a correct trace. The server is receiving and sending its data. However, as before, I am not in no-wait mode. And so the copy fails. I have looked deeply in the code of all existing protocols but found nothing.. Does anybody have a clue? Regards Patrick