问题
I have been on learning Ocaml for a week, some things got clear, the others rather not. I'm trying to compose a simple Tic-Tac-Toe server accepting connections via telnet. Just for a word. I have to use Lwt and rigth now it seems for me a darken place because I had faced too much of language pecularities. The begining of the code:
let sock = Lwt_unix.socket Unix.PF_INET Unix.SOCK_STREAM 0
let setting_up_server_socket =
let sockaddr = (Unix.ADDR_INET(Unix.inet_addr_of_string "127.0.0.1", 23233)) in
Lwt_unix.set_close_on_exec sock;
Lwt_unix.setsockopt sock Unix.SO_REUSEADDR true;
Lwt_unix.bind sock sockaddr;
Lwt_unix.listen sock 20
OK, that's clear. The server socket is set to listen for clients connections. Let's try to get a first guest:
let handle_income =
Lwt_unix.accept sock;;
Seems to be clear, but:
val handle_income : (Lwt_unix.file_descr * Lwt_unix.sockaddr) Lwt.t = <abstr>
Here I'm stacked. I don't know even how to send a message to client socket. Unlike general Unix.accept it returns ('a * 'b) Lwt.t. Some questions:
- How can I get pure client "Lwt_unix.file_descr" from that?
- ('a * 'b) Lwt.t. is a tuple belonging to Lwt.t object, isn't it? Or it just a field? I am confused at all.
P.S. Sorry if my English is not acceptable. I was learning it long time ago. As the question is already asked please give a piece of advise, where I can get the best information about Ocaml. The best a mean short/clearness. Due reading O'REILLY I instantly forget what I was reading 5 min ago because it's never clear what this or that the author talking about is used for. Ocaml is quite different with Java and JS I had started with.
回答1:
A value of type 'a Lwt.t
represents a thread that will evaluate to a value of type 'a
once it is ready (or to an error is something went wrong). The only way to get 'a
from 'a Lwt.t
is to bind it to another function, that will be called as soon, as 'a Lwt.t
thread is finished and data is ready. You can bind with Lwt.bind
function, also available in an infix notation >>=
.
For example:
let process_client fd =
Lwt_unix.accept fd >>= fun (cli,sock) ->
let chan = Lwt_io.(of_fd ~mode:output cli) in
Lwt_io.fprintf chan "hi there, and bye!" >>= fun () ->
Lwt_io.close chan
This uses infix notation, you can rewrite it more verbose:
let reply chan =
Lwt_io.fprintf chan "hi there, and bye!"
let finish chan = Lwt_io.close chan
let create_chan = Lwt_io.(of_fd ~mode:output cli)
let process_client fd =
let accept_t = Lwt_unix.accept fd in
let chan_t = Lwt.map accept_t create_chan in
let reply_t = Lwt.bind accept_t reply in
Lwt.bind reply_t finish
Where _t
designates thread
. I.e., accept_t
is a thread that will eventually return a pair of a file descriptor and a socket address. chan_t
is a thread that will return a channel (for doing buffered io).
Lwt
also comes with a support for special syntax. Actually with support for two syntaxes, the old with camlp4 and a newer one with ppx. In old syntax, one can write the process_client
function as follows:
let process_client fd =
lwt (cli,sock) = Lwt_unix.accept fd in
let chan = Lwt_io.(of_fd ~mode:output cli) in
lwt () = Lwt_io.fprintf chan "hi there, and bye!" in
Lwt_io.close chan
There lwt
is a special form of let
that not only binds names to values, but also waits for them to evaluate.
I hope that I answered all your questions. You may also find this library interesting.
P.S. I didn't test the code, so if you have any issues, don't hesitate to ask.
P.P.S. I left a proper shutdown
procedure, to keep code simple.
来源:https://stackoverflow.com/questions/32102949/working-with-ocaml-lwt-sockets