[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: asynchronous socket library
From: |
Mark H Weaver |
Subject: |
Re: asynchronous socket library |
Date: |
Sat, 24 Aug 2013 17:33:05 -0400 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/24.3 (gnu/linux) |
Hi Mark,
Sorry for taking so long to respond.
address@hidden writes:
> Mark H Weaver <address@hidden> writes:
>
>> address@hidden writes:
>>> Reading and writing to a socket seems to lend itself well to custom
>>> binary ports,
>>
>> Why do you say that? For most purposes, Guile's native file ports are
>> superior, and they seem the natural choice for sockets.
>>
>
> I over-generalized. In my application, I'm using the X protocol, which
> is a binary one. I've been so involved with that I forgot that much of
> the time you want to read/write character data from a socket.
Guile's native file ports (which also work on sockets) can be used for
binary data as well as character data. There's no need to create a
custom binary port for this purpose. Indeed, the custom ports have
several major disadvantages compared to the native file ports.
>> 'get-bytevector-some' from (rnrs io ports) might do what you need. If
>> there's at least one byte available it will not block, but in practice
>> it reads much more than that (for buffered ports). Guile 2.0.9 has a
>> nice fast implementation. Prior to 2.0.9, it was less so.
>>
>> In more detail: as of 2.0.9, 'get-bytevector-some' will simply copy the
>> input buffer managed by Guile into a bytevector and return it. If
>> Guile's input buffer is empty, it will try to refill the buffer using
>> the port type's 'fill_input' method. For file ports this is
>> fports.c:fport_fill_input, and for custom binary ports it's
>> r6rs-ports.c:cbip_fill_input.
>
> In order to know if the port has at least one byte ready, you need to be
> able to call 'char-ready?', don't you? And as you mentioned, that
> doesn't work on custom binary ports. I'm still exploring this part of
> Guile so I might not have the details right.
>
>>
>> So again I ask, why use custom binary ports for sockets?
>>
>
> Thanks for the detailed explanation; I think I'll move away from
> them. Were they added just to meet the r6rs spec? Are there any good
> uses for custom binary ports that you're aware of?
Yes, custom ports are needed if the data that's being read is not coming
from a file, pipe, device, socket, string, or bytevector (the cases
covered by Guile's existing native port types; maybe I'm forgetting
some). Similarly for writing.
For example, suppose you wanted a make an input port that reads
keypresses from a GUI interface. In this case, the keypresses are
received via events during the main event loop. There is no underlying
POSIX file descriptor to read from, nor is there a single Scheme string
or bytevector. You could use pipes I suppose, but that assumes POSIX.
Another way is to make a custom port.
In the case of guile-xcb, I see two places where custom ports are used
in auth.scm. Here's the first case:
--8<---------------cut here---------------start------------->8---
(define auth-file (open-file (getenv "XAUTHORITY") "rb"))
(define port
(make-custom-binary-input-port
"xcb-auth-input"
(lambda (bv start count)
(do ((n 0 (1+ n))
(ch (read-char auth-file) (read-char auth-file)))
((or (>= n count) (eof-object? ch)) n)
(bytevector-u8-set!
bv (+ start n) (char->integer ch))))
#f #f (lambda () (close-port port))))
--8<---------------cut here---------------end--------------->8---
First of all, that '(close-port port)' is wrong. Here you are trying to
tell Guile how to close 'port', and this just recurses. I guess it
should be (close-port auth-file)'.
However, I don't see why this custom port is needed at all. You've
already opened 'auth-file' in binary mode, so you should be able to use
it directly, i.e. replace the above code with:
(define port (open-file (getenv "XAUTHORITY") "rb"))
The other case is here (also in auth.scm):
--8<---------------cut here---------------start------------->8---
(define (read! bv start count)
(let* ((in-bv (make-bytevector count))
(bytes-read (recv! sock in-bv)))
(bytevector-copy! in-bv 0 bv start bytes-read)
bytes-read))
(define port (make-custom-binary-input-port "xcb-input" read! #f #f #f))
--8<---------------cut here---------------end--------------->8---
Again, I don't see why this custom port should be needed.
You should be able to use 'sock' directly.
Anyway, thanks for working on this! :)
Regards,
Mark
- Re: asynchronous socket library,
Mark H Weaver <=