[plt-scheme] telnet client in scheme
These two functions have been pretty useful for me. I use them in all the
client/server programs I write. The code is based on code Shriram wrote for
Teach Scheme! 2 but changed so that each function takes a function which
takes an input and an output port.
;; open-connection: (String Integer (InputPort OutputPort -> void) -> void)
;; open a connection to a machine and pass the ports to a handler
(define (open-connection machine port handler)
(let-values ([(server->me me->server)
(tcp-connect machine port)])
(handler server->me me->server)
(close-output-port me->server)
(close-input-port server->me)))
;; install-listener: (Integer (InputPort OutputPort -> void) -> void)
;; creates a listener in a thread of its own and calls handler with the ports
(define (install-listener port handler)
(let ([listener (tcp-listen port)])
(with-handlers ([exn:break?
(lambda (exn)
(tcp-close listener))])
(let loop ()
(let-values ([(client->me me->client)
(tcp-accept listener)])
(thread
(lambda ()
(handler client->me me->client)
(close-input-port client->me)
(close-output-port me->client))))
(loop)))))
-mike
On Thu, Jun 05, 2003 at 02:03:56AM +0200, Toon wrote:
> For list-related administrative tasks:
> http://list.cs.brown.edu/mailman/listinfo/plt-scheme
>
> Here's a simple client I've written to make chatprogs and stuff...
> The client starts to try to connect to a server from the moment you ask
> your client to connect, on failure he automatically tries to connect
> again...
> Use (client 'disconnect) to disconnect or stop the attempt...
>
> Hope it will help you with wathever you wanted to do... It works totally
> the same as telnet anyway...
>
> Greetz.
> toon
>
> Usage:
>
> (define client (create-basic-client <inputmanager>)) => inputmanager could
> be display, anyway a proc with 1 var
> (client 'set-ip "<ip-address>")
> (client 'set-port <port>)
> (client 'connect)
>
> then use
>
> (client "<msg>") to write to server => When you work graphical the msg will
> be a string anyway, so this
> is the easiest way
> ...
>
>
> the basic-client code:
>
> (define (create-basic-client inputmanager)
> (letrec [;;ServerIP
>
> (ip #f)
>
> ;;Serverport
>
> (port #f)
>
> ;;Inputport
>
> (input #f)
>
> ;;Outputport
>
> (output #f)
>
> ;;Are you currently trying to connect to server?
>
> (trying-to-connect? #f)
>
> ;;The reading-thread
>
> (return-loop-thread #f)
>
> ;;Connecting to server
>
> (connect (lambda ()
> (if (and (not input) (not output) ip port)
> (set! return-loop-thread (thread (lambda ()
>
> (error-display-handler connection-error-manager)
> (set!
> trying-to-connect? #t)
>
> (call-with-values
> (lambda ()
> (tcp-connect ip port))
> (lambda
> (inputport outputport)
> (set! input
> inputport)
> (set! output
> outputport)))
> (set!
> trying-to-connect? #f)
>
> (return-loop)))))))
>
> ;;Disconnecting from server
>
> (disconnect (lambda (reconnect?)
> (if return-loop-thread
> (begin
> (if (output-port? output)
> (close-output-port output))
> (if (input-port? input)
> (close-input-port input))
> (set! input #f)
> (set! output #f)
> (if reconnect?
> (read-me 'connect)
> (begin
> (kill-thread return-loop-thread)
> (set! return-loop-thread #f)))))))
>
> ;;Reading servermsg's and sending them to the inputmanager
>
> (return-loop (lambda ()
> (let [(data (read-line input))]
> (if (eof-object? data)
> (begin
> (inputmanager "DISCONNECTED")
> (read-me 'disconnect 'reconnect))
> (begin
> (inputmanager (car (split data "\r")))
> (return-loop))))))
>
> ;;Automatically reconnecting on failure while trying to connect
>
> (connection-error-manager (lambda (string struct)
> (if trying-to-connect?
> (begin
> (set! input #f)
> (set! output #f)
> (read-me 'connect)))))
>
> ;;Abstractions of the ADT and server-output-manager
>
> (read-me (lambda (m . args)
> (case m
> ((connect) (connect))
> ((disconnect) (disconnect (pair? args)))
> ((set-ip) (if (not (null? args)) (set! ip (car
> args))))
> ((set-port) (if (not (null? args)) (set! port (car
> args))))
> ((delete-ip) (set! ip #f))
> ((delete-port) (set! port #f))
> (else (if (and output (string? m))
> (display (string-append m "\r\n") output)
> #f)))))]
> read-me))
> ----- Original Message -----
> From: "Neil W. Van Dyke" <neil at neilvandyke.org>
> To: "Chris" <chris81 at wanadoo.fr>
> Cc: "ml plt scheme" <plt-scheme at qua.cs.brown.edu>
> Sent: Wednesday, June 04, 2003 1:47 PM
> Subject: Re: [plt-scheme] telnet client in scheme
>
>
> > For list-related administrative tasks:
> > http://list.cs.brown.edu/mailman/listinfo/plt-scheme
> >
> > Chris <chris81 at wanadoo.fr> writes at 12:13 04-Jun-2003 +0200:
> > > I just want to know if a client telnet made in scheme allready exist and
> >
> > One might exist (I don't know), but writing your own is a really good
> > learning exercise.
> >
> > > and it's send me nothing back but i see the connexion opened in the
> telnetd
> > > log. Am I missing something ?
> >
> > Perhaps the Telnet server is not sending a full line; for example, maybe
> > it's just sending "Password: " without a newline sequence. Or maybe
> > it's using a nonstandard newline convention, like CR (PLT's "read-line"
> > can be made to handle this, but there's a better way).
> >
> > Instead of using "read-line", you probably want your code to read single
> > characters or blocks of characters, rather than waiting for the server
> > to send a newline. You will need this for other parts of the protocol
> > anyway. Here's a simple variation on the code you posted:
> >
> > (display "*DEBUG* Connecting...\n")
> >
> > (define-values (p-in p-out) (tcp-connect "host" 23))
> >
> > (display "*DEBUG* Connected.\n")
> >
> > (let loop ()
> > (display "*DEBUG* Waiting for character...\n")
> > (let ((c (read-char p-in)))
> > (printf "*DEBUG* Read character: ~S\n" c)
> > (loop)))
> >
> > If this code doesn't read any characters from your Telnet server, then
> > it could be waiting for the client to send one or more newlines or it
> > could be waiting for the client to initiate a cryptographic
> > authentication. Don't think too hard about "*DEBUG*" messages that
> > aren't appearing, since they might be stuck in unflushed I/O buffers.
> > Try running a protocol sniffer or packet analyzer, like the free
> > Ethereal, while you connect to your Telnet server with your system's
> > Telnet client, to see how it works.
> >
> > Once you can read and write single characters with your Telnet server,
> > take a look at the PLT procedures "read-string-avail!/enable-break" and
> > "write-string-avail/enable-break", and "object-wait-multiple" for how to
> > do this robustly and more efficiently.
> >
> > Searching for "telnet" from "http://www.rfc-editor.org/rfcsearch.html"
> > yields over 100 documents, most of which are not relevant to you. RFC
> > 318 ("ftp://ftp.rfc-editor.org/in-notes/rfc318.txt") might be a good
> > starting point.
> >
> > --
> > http://www.neilvandyke.org/
>