Version française
Home     About     Download     Resources     Contact us    
Browse thread
[Caml-list] cdk & glob
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Felix Terkhorn <masterkh@i...>
Subject: Re: [Caml-list] Socket example
dsfox@cogsci.ucsd.edu wrote:
> If anyone can forward me a dead simple example of using the ocaml Unix
> module to open a socket pair to a server and reading and writing to
> it, I would be very grateful.

Here's a pretty simple example.  First of all, get two terminals open:
one is going to be your 'client' terminal, and the other, your
'server' terminal.  Run OCaml toplevel on both (one that has support
for the Unix library).  Now, on each terminal, type this:


let sock = socket PF_INET SOCK_STREAM 0;;


This will give you an unconnected/unbound socket descriptor with which
to play.  Now, on the server terminal, type:


bind sock (ADDR_INET (inet_addr_of_string "127.0.0.1",55555));;
listen sock;;
let (client_sock,client_addr) = accept sock;;



"bind" hooks up the socket to a specific IP address and port.  Here,
we use 127.0.0.1:55555.  We write inet_addr_of_string "127.0.0.1"
because OCaml expects to receive its own type of ip address
abstraction.  inet_addr_of_string creates that.  ADDR_INET simply tags
the inet_addr and port number as a 'sockaddr'.

"listen" flags the socket as "listening," ie, it should be expecting
to receive a connection from somewhere in the internet.

"accept" places the program in a wait-state until a connection has
been made with another socket.  When that connection is made, accept
returns a tuple consisting of the client socket and the address from
which the client is connecting.  The original socket is not changed:
it is now dedicated to handling "incoming calls."  Instead, a new
socket is connected on another port, and that is the socket through
which the server can communicate with its client.

Remember: the server must bind, then listen, then accept to receive
connections.


Now, on the client terminal, type:


connect sock (ADDR_INET (inet_addr_of_string "127.0.0.1",55555));;


This hooks up the socket on the client side to the socket on the
server side.

So on the client side, we can do


send sock "hello" 0 5 [];;


and that will send the string "hello" (starting at index 0, and taking
a slice of 5 characters) across the socket.  The empty list is a list
"message flags."  Since I don't know what they do, I haven't put any
in the list. :)

Then, on the server side, we can do


let buf = String.create 32;;
recv client_sock buf 0 5 [];;


recv works basically like send... and they both work more or less like
Unix.read and Unix.write.  'buf' is the string that is to be
side-effected by recv when it gets data from the socket.  If you look
at 'buf' after this call, you'll see (hopefully) 'hello' sitting at
the front of the string.

send and recv both return how many characters they sent or received,
respectively.  Keep in mind that you may have to do multiple
sends/recvs in order to get very large chunks of text across.  One way
to handle this a little more elegantly is to do something like


let (sock_in,sock_out) = 
   (in_channel_of_descr sock,out_channel_of_descr sock);;


which should work on the client side (or the server side, if you
change 'sock' to 'client_sock'), and which will let you then use all
of the pervasive library's input and output functions on the "socket
channels" you've created, eg...


output_string sock_out "i (heart) ocaml";;
flush sock_out;;
input_string sock_in  (* and hope the other side has sent something back *)


This is a lot nicer than messing with side-effecting and string
buffers, IMHO.  Just don't forget to flush. ;)

Hope this helps.

Felix


-- 
'(felix-terkhorn . masterkh@indiana.edu)