Arc Forumnew | comments | leaders | submitlogin
arc telnet
5 points by bOR_ 5833 days ago | 16 comments
There was a request 87 days ago for the ability to connect to a remote tcp port (jgrahamc). I'm interested in that as well (well, actually telnet). Is that easy to do by adding some xdefs to ac.scm?

Merely adding (xdef 'tcp-connect tcp-connect) to ac.scm puts me in a little bit of trouble (both in mzscheme and in arc).

In mzscheme it gives me two values in return which I can't car

  > (tcp-connect "avendar.com" 9999)
  #<input-port>
  #<output-port>
  > (car (tcp-connect "avendar.com" 9999))
  context expected 1 value, received 2 values:   #<input-port> #<output-port>
And similar in arc

  arc> (tcp-connect "avendar.com" 9999)
  Error: "context expected 1 value, received 2 values: #<input-port> #<output-port>"


6 points by stefano 5832 days ago | link

In anarki there is the function connect-socket, I think it is just what you want (have a look at the end of the ac.scm file, just before thread local vars).

-----

1 point by bOR_ 5832 days ago | link

Could be. Right now I'm still using the regular arc2, and am now trying to figure out how to deal with the input of the mud, if I've to make separate threads for reading and writing input, or that I can make use of peekc in some way to figure out when the mud has stopped sending characters to the input port. It is fun though :)

  (= inout (tcp-connect "avendar.com" 9999))
  (#<input-port> #<output-port>)
  arc> (while (peekc (car inout)) (pr (readc (car inout))))

-----

1 point by bOR_ 5831 days ago | link

Hmm. still a bit puzzled. I seem able to read (in various ways readc, readline) no problem, but writing to cadr inout doesn't seem to trigger new input from the mud to read.

All of you, thanks for the help so far. I'll tinker on with it later, time for my primary arc project ;).

-----

2 points by stefano 5831 days ago | link

For the output problem, try flushing the out stream with flush-socket on Anarki or the corresponding flush-output from mzscheme, maybe the output is written to a buffer and there is not enough information to send to force the buffer to be flushed.

-----

1 point by bOR_ 5831 days ago | link

Thanks for the flush-output thing, but it seems I will first have to work my way past the readc / peekc problem.

(avendar is down right now, so if anyone is trying to help out, use another mud / telnet server)

  arc> (readc (car inout))
  #\M
  arc> (readc (car inout))
  #\o
  arc> (readc (car inout))
  #\u
  arc> (readc (car inout))
  #\r
  arc> (readc (car inout))
  #\n
  arc> (readc (car inout))
  #\e
  arc> (readc (car inout))
  #\d
  arc> (readc (car inout))
  #\?

  arc> (peekc (car inout))
  #\space
  arc> (readc (car inout))
  #\space

  arc> (peekc (car inout))
  #\u0001
  arc> (readc (car inout))
  #\u0001

  arc> (peekc (car inout))
  user break
peekc hangs when I'm reading the output from telnet, but works fine (returning nil) when I'm reading out the output after the last char from a stored pipe.

  arc> (= answer (pipe-from "echo hello"))

  arc> (readc answer)
  #\l
  arc> (readc answer)
  #\o
  arc> (readc answer)
  #\newline
  arc> (peekc answer)
  nil
  arc> (peekc answer)
  nil
  arc> (readc answer)
  nil

-----

2 points by almkglor 5830 days ago | link

In my experience peekc doesn't seem to work properly (i.e. as advertised) at all.

I assume you're doing peekc so that you can do something else while waiting for a character? If that is what you're trying to do, I suggest you use threads:

  (let ch nil
    (thread (= ch (readc:car inout)))
    (while (no ch)
      (do-something-while-waiting))
    (do-something-with ch))

-----

1 point by bOR_ 5824 days ago | link

(waiting for a program to calculate the variation in epitope clusters, so working on this for a moment)

  (= mudpipe (tcp-connect "avendar.com" 9999))

  (def readmud ()
     (let ch nil
       (thread (= ch (readc:car mudpipe)))
       (while (no ch)
       ; wait patiently
       )
     (pr ch)
     (readmud)))

  (= mudreader (new-thread readmud))

(first time I work with threads) readmud only reads one character at a time, and I want it to just keep on writing as long as there is data. I'll try to add a thread that calls readmud again the moment it returns something sensible.

Partial success. The reading bit seems to function fine (if slow ;), and I now can use arc while in the background the muds' output is being read, but still cannot write. Did add mzscheme's flush-out (but perhaps in some wrong way. Will look at it during the next work-break ;).

-----

1 point by almkglor 5823 days ago | link

Err. If you're just waiting patiently.... why not just readc directly?

  (def readmud ()
    (pr:readc:car mudpipe)
    (readmud))

-----

1 point by stefano 5830 days ago | link

Maybe the problem with peekc is that it tries to read a character from the socket, but the server has yet to write that character, and peekc doesn't return nil because the server hasn't yet closed its output stream, so there is no end-of-file.

-----

1 point by absz 5832 days ago | link

Hey, that is there. That's convenient.

-----

2 points by absz 5833 days ago | link

Your problem is that tcp-connect returns multiple values; not a list, but multiple values. What you need to do is extract the two values into a list, and return them. This can be done via mzscheme's call-with-values procedure, takes two functions; the first is called with no arguments, and generates multiple values; the second is called on all of the values. Thus, you want, if memory serves, the entirely untested

  (xdef 'tcp-connect
        (lambda (host port . rest)
          (call-with-values
            (lambda () (apply tcp-connect host port rest))
            list)))
Give that a shot, and see if it works.

I never knew that mzscheme had multiple return values… learn something new every day, I guess!

-----

1 point by bOR_ 5833 days ago | link

It works! (with the occasional error message)

  arc> (= inout cons)
  #<primitive:cons>
  arc> (= inout (tcp-connect "avendar.com" 9999))
  (#<input-port> #<output-port>)

   
  arc> (read (car inout))
  Avendar
  arc> (read (car inout))
  created
  arc> (read (car inout))
  by
  arc> (read (car inout))
  Matt
  arc> (read (car inout))
  Wallace
  arc> (read (car inout))
  (unquote Thane)
  arc> (read (car inout))
  Williams

-----

1 point by almkglor 5832 days ago | link

Why do you assign 'cons to 'inout?

Anyway I suggest you push it on Anarki^^

-----

1 point by bOR_ 5832 days ago | link

Why? because there isn't that much in lisp/scheme/arc that comes naturally to me :).

Not sure about how to go about pushing something on something else. Never been in an environment where we worked with cvs or git or anything. Solitary scientists :)

-----

1 point by almkglor 5832 days ago | link

Might be better:

  (xdef 'tcp-connect
        (lambda (host port . rest)
          (call-with-values
            (lambda () (apply tcp-connect host port rest))
            (lambda (x y)
              (cons x (cons y 'nil))))))

-----

1 point by absz 5832 days ago | link

Ouch, I hadn't thought of that. But I just tested this, and it appears that ac.scm runs the translation step after the xdefed functions return, so we get a valid Arc list back. Saved by the bell, so to speak :)

-----