(* ================================================================== *) (* == POD 98-99 -- *) (* ------------------------------------------------------------------ *) (* == Client/Serveur via Internet : Hello v.01 *) (* La version de base du serveur *) (* ------------------------------------------------------------------ *) (* ocamlc -custom unix.cma hello1d.ml -o hello1d -cclib -lunix *) (* ================================================================== *) open Unix ;; (* == val get_s_port : string -> int *) (* Calcule le numero de port du service en fonction de son argument *) let get_s_port p_num = try int_of_string p_num with Failure("int_of_string") -> failwith("incorrect port number "^p_num) ;; (* == val message : Unix.sockaddr -> string *) (* Compose le message de reponse a la connection d'un client *) let message = function ADDR_UNIX _ -> "\n Hum, something's strange with this UNIX socket\n" |ADDR_INET(cl_inet_addr,_) -> ("Hello "^((gethostbyaddr cl_inet_addr).h_name) ^" ("^(string_of_inet_addr cl_inet_addr)^")\n") ;; (* == val server : unit -> unit *) (* Le serveur *) let server () = (* Si pas d'argument : erreur *) if Array.length Sys.argv < 2 then begin Printf.eprintf "Usage : hello1d portnumber\n" end (* sinon *) else (* Lecture du numero de port du service *) let port = get_s_port Sys.argv.(1) in (* Creation de la socket de service *) let sock = socket PF_INET SOCK_STREAM 0 in (* Adresse du serveur *) let h_addr = (gethostbyname (gethostname())).h_addr_list.(0) in (* Adresse de la socket *) let sock_addr = ADDR_INET(h_addr, port) in begin (* Liaison socket/adresse *) bind sock sock_addr; (* Mise en attente de connection *) listen sock 5; (* Boucle de service *) while true do (* On accepte une connexion *) let (cl_sock, cl_sock_addr) = accept sock in (* On cree un processus de traitement de la connexion (le fils) *) if fork() == 0 then begin (* Hack Unix :-) *) if fork()<>0 then exit 0; (* Emission du message de reponse *) (let m = message cl_sock_addr in write cl_sock m 0 (String.length m)); (* Fermeture de la socket client *) close cl_sock; (* Fin du processus de traitement de connexion *) exit 0 end else (* Le pere *) (* Attente fin de traitement connexion (par le fils) *) let _ = wait() in close cl_sock done end ;; (* == Programme principal *) try server() with Unix_error(c,f,x) -> Printf.eprintf "\n %s in %s %s\n" (error_message c) f x |Failure x -> Printf.eprintf "\n %s \n" x ;;
Le client :
demande une connexion et attend une réponse qu'il affiche sur
sa sortie standard
Commande : hello1 serveur.domaine numport où
serveur.domaine est l'adresse IP du serveur et
numport le numéro de port du service
Code :
(* ================================================================== *)
(* == POD 98-99 -- *)
(* ------------------------------------------------------------------ *)
(* == Client/Serveur via Internet : Hello v.01 *)
(* La version de base du client *)
(* ------------------------------------------------------------------ *)
(* ocamlc -custom unix.cma hello1.ml -o hello1 -cclib -lunix *)
(* ================================================================== *)
open Unix
;;
(* == val get_in_addr : string -> Unix.inet_addr *)
(* Calcule l'adresse IP du serveur en fonction de son argument *)
let get_in_addr host =
try
(* on essaie 'machine.domaine' *)
(gethostbyname host).h_addr_list.(0)
with
Not_found
-> try
(* sinon : x.y.z.w *)
inet_addr_of_string host
with
Failure "inet_addr_of_string" -> failwith("unknown host "^host)
;;
(* == val get_s_port : string -> int *)
(* Calcule le numero de port du service en fonction de son argument *)
let get_s_port port =
try int_of_string port with
Failure("int_of_string") -> failwith("incorrect port number "^port)
;;
(* == val client : unit -> unit *)
(* Le client *)
let client () =
(* Si pas assez d'arguments : erreur *)
if Array.length Sys.argv < 3 then
begin
Printf.eprintf "Usage : hello1 hostname portnumber\n"
end
(* sinon *)
else
(* Adresse du serveur (1ier argument) *)
let in_addr = get_in_addr Sys.argv.(1) in
(* Port de connexion (2nd argument) *)
let s_port = get_s_port Sys.argv.(2) in
(* Creation de la socket de service *)
let sock = socket PF_INET SOCK_STREAM 0 in
begin
(* Connexion *)
connect sock (ADDR_INET(in_addr, s_port));
(* Lecture et affichage de la reponse *)
let r = input_line (in_channel_of_descr sock) in
Printf.printf "(%d) %s\n" (String.length r) r;
flush (out_channel_of_descr stdout)
end
;;
(* == Programme principal *)
try
client()
with
Unix_error(c,f,x)
-> Printf.eprintf "\n %s in %s %s\n" (error_message c) f x
;;
(* ================================================================== *) (* == POD 98-99 -- *) (* ------------------------------------------------------------------ *) (* == Client/Serveur via Internet : Hello v.02 *) (* La version du client avec delai d'attente pour la reponse *) (* ------------------------------------------------------------------ *) (* ocamlc -custom unix.cma hello2.ml -o hello2 -cclib -lunix *) (* ================================================================== *) open Unix ;; (* == val get_in_addr : string -> Unix.inet_addr *) (* Calcule l'adresse IP du serveur en fonction de son argument *) let get_in_addr host = try (* on essaie 'machine.domaine' *) (gethostbyname host).h_addr_list.(0) with Not_found -> try (* sinon : x.y.z.w *) inet_addr_of_string host with Failure "inet_addr_of_string" -> failwith("unknown host "^host) ;; (* == val get_s_port : string -> int *) (* Calcule le numero de port du service en fonction de son argument *) let get_s_port port = try int_of_string port with Failure("int_of_string") -> failwith("incorrect port number "^port) ;; (* == val client : unit -> unit *) (* Le client *) let client () = (* Si pas assez d'arguments : erreur *) if Array.length Sys.argv < 3 then begin Printf.eprintf "Usage : hello2 hostname portnumber\n" end (* sinon *) else (* Delai maximal d'attente *) let timeout = 5 in (* Adresse du serveur (1ier argument) *) let in_addr = get_in_addr Sys.argv.(1) in (* Port de connexion (2nd argument) *) let s_port = get_s_port Sys.argv.(2) in (* Creation de la socket de service *) let sock = socket PF_INET SOCK_STREAM 0 in (* On cree un processus de d'attente de la reponse (le fils) *) if fork() = 0 then begin (* On declenche le compte a rebours *) alarm timeout; (* Connexion *) connect sock (ADDR_INET(in_addr, s_port)); (* Lecture et affichage de la reponse *) let r = input_line (in_channel_of_descr sock) in (Printf.printf "(%d) %s\n" (String.length r) r; flush (out_channel_of_descr stdout)); (* Fermeture de la socket *) close sock; (* Fin du traitement *) exit 0 end else (* Le pere *) begin (* Fermeture de la socket *) close sock; (* Attente et analyse fin du fils *) (match wait() with (* Fin normale *) (_,WEXITED 0) -> () (* Fin hors delai *) |(_,WSIGNALED 14) -> Printf.printf"Terminated after timeout %d sec.\n" timeout (* Autres cas *) |_ -> Printf.eprintf"Unexpected terminaison\n") end ;; (* == Programme principal *) try client() with Unix_error(c,f,x) -> Printf.eprintf "\n %s in %s %s\n" (error_message c) f x ;;
Version avec acquittement
Le serveur : attend une connexion, renvoie un message du genre (26) Hello machine.client (772) au client qui s'est connecté depuis la machine machine.client et attend un acquittement du client
Commande : hello2d numport& où numport est le numéro de port du service
Code :(* ================================================================== *) (* == POD 98-99 -- *) (* ------------------------------------------------------------------ *) (* == Client/Serveur via Internet : Hello v.02 *) (* La version du serveur avec attente d'acquitement *) (* ------------------------------------------------------------------ *) (* ocamlc -custom unix.cma hello2d.ml -o hello2d -cclib -lunix *) (* ================================================================== *) open Unix ;; (* == val get_s_port : string -> int *) (* Calcule le numero de port du service en fonction de son argument *) let get_s_port p_num = try int_of_string p_num with Failure("int_of_string") -> failwith("incorrect port number "^p_num) ;; (* == val message : Unix.sockaddr -> string *) (* Compose le message de reponse a la connection d'un client *) let message = function ADDR_UNIX _ -> "\n Hum, something's strange with this UNIX socket\n" |ADDR_INET(cl_inet_addr,_) -> ("Hello "^((gethostbyaddr cl_inet_addr).h_name) ^" ("^(string_of_inet_addr cl_inet_addr)^")\n") ;; (* == val server : unit -> unit *) (* Le serveur *) let server () = (* Si pas d'argument : erreur *) if Array.length Sys.argv < 2 then begin Printf.eprintf "Usage : hello2d portnumber\n" end (* sinon *) else (* Lecture du numero de port du service *) let port = get_s_port Sys.argv.(1) in (* Creation de la socket de service *) let sock = socket PF_INET SOCK_STREAM 0 in (* Adresse du serveur *) let h_addr = (gethostbyname (gethostname())).h_addr_list.(0) in (* Adresse de la socket *) let sock_addr = ADDR_INET(h_addr, port) in begin (* Liaison socket/adresse *) bind sock sock_addr; (* Mise en attente de connection *) listen sock 5; (* Boucle de service *) while true do (* On accepte une connexion *) let (cl_sock, cl_sock_addr) = accept sock in (* On cree un processus de traitement de la connexion (le fils) *) if fork() == 0 then begin (* Hack Unix :-) *) if fork()<>0 then exit 0; (* Emission du message de reponse *) (let m = message cl_sock_addr in write cl_sock m 0 (String.length m)); (* Lecture de l'acquitement *) (let r = String.make 2 '\000' in read cl_sock r 0 2); (* Fermeture de la socket client *) close cl_sock; (* Fin du processus de traitement de connexion *) exit 0 end else (* Le pere *) (* Attente fin de traitement connexion (par le fils) *) let _ = wait() in close cl_sock done end ;; (* == Programme principal *) try server() with Unix_error(c,f,x) -> Printf.eprintf "\n %s in %s %s\n" (error_message c) f x |Failure x -> Printf.eprintf "\n %s \n" x ;;
Un client avec délai d'attente et acquittement
Le client : demande une connexion et attend une réponse dans un certain délai. Lorsqu'il reçoit une réponse, il émet un acquittement. Il affiche soit le message reçu soit le message Terminated after timeout 5 sec.
Commande : hello3 serveur.domaine numport où serveur.domaine est l'adresse IP du serveur et numport le numéro de port du service
Code :(* ================================================================== *) (* == POD 98-99 -- *) (* ------------------------------------------------------------------ *) (* == Client/Serveur via Internet : Hello v.03 *) (* La version du client avec delai d'attente pour la reponse et *) (* acquittement *) (* ------------------------------------------------------------------ *) (* ocamlc -custom unix.cma hello3.ml -o hello3 -cclib -lunix *) (* ================================================================== *) open Unix ;; (* == val get_in_addr : string -> Unix.inet_addr *) (* Calcule l'adresse IP du serveur en fonction de son argument *) let get_in_addr host = try (* on essaie 'machine.domaine' *) (gethostbyname host).h_addr_list.(0) with Not_found -> try (* sinon : x.y.z.w *) inet_addr_of_string host with Failure "inet_addr_of_string" -> failwith("unknown host "^host) ;; (* == val get_s_port : string -> int *) (* Calcule le numero de port du service en fonction de son argument *) let get_s_port port = try int_of_string port with Failure("int_of_string") -> failwith("incorrect port number "^port) ;; (* == val client : unit -> unit *) (* Le client *) let client () = (* Si pas assez d'arguments : erreur *) if Array.length Sys.argv < 3 then begin Printf.eprintf "Usage : hello2 hostname portnumber\n" end (* sinon *) else (* Delai maximal d'attente *) let timeout = 5 in (* Adresse du serveur (1ier argument) *) let in_addr = get_in_addr Sys.argv.(1) in (* Port de connexion (2nd argument) *) let s_port = get_s_port Sys.argv.(2) in (* Creation de la socket de service *) let sock = socket PF_INET SOCK_STREAM 0 in (* Processus de d'attente et traitement de la reponse (le fils) *) if fork() = 0 then begin (* On declenche le compte a rebours *) alarm timeout; (* Connexion *) connect sock (ADDR_INET(in_addr, s_port)); (* Lecture et affichage de la reponse *) let r = input_line (in_channel_of_descr sock) in (Printf.printf "(%d) %s\n" (String.length r) r; flush (out_channel_of_descr stdout)); (* Emission de l'acquitement *) write sock "OK" 0 2; (* Fermeture de la socket *) close sock; (* Fin du traitement *) exit 0 end else (* Le pere *) begin (* Fermeture de la socket *) close sock; (* Attente et analyse fin du fils *) (match wait() with (* Fin normale *) (_,WEXITED 0) -> () (* Fin hors delai *) |(_,WSIGNALED 14) -> Printf.printf"Terminated after timeout %d sec.\n" timeout (* Autres cas *) |_ -> Printf.eprintf"Unexpected terminaison\n") end ;; (* == Programme principal *) try client() with Unix_error(c,f,x) -> Printf.eprintf "\n %s in %s %s\n" (error_message c) f x ;;
Version avec trace des connexions
Le serveur : attend une connexion, renvoie un message du genre (26) Hello machine.client (772) au client qui s'est connecté depuis la machine machine.client et attend un acquittement du client. Il produit de plus une trace des connexions et des réceptions d'acquittement dans un fichier hello.log
Commande : hello3d numport& où numport est le numéro de port du service
Code :(* ================================================================== *) (* == POD 98-99 -- *) (* ------------------------------------------------------------------ *) (* == Client/Serveur via Internet : Hello v.03 *) (* La version du serveur avec attente d'acquitement et ecriture d'une *) (* trace dans un fichier 'hello.log' *) (* ------------------------------------------------------------------ *) (* ocamlc -custom unix.cma hello3d.ml -o hello3d -cclib -lunix *) (* ================================================================== *) open Unix (* == val get_s_port : string -> int *) (* Calcule le numero de port du service en fonction de son argument *) let get_s_port p_num = try int_of_string p_num with Failure("int_of_string") -> failwith("incorrect port number "^p_num) ;; (* == val get_cl_name : Unix.sockaddr -> string *) (* Extrait le nom du client a partie de sont addresse IP *) let get_cl_name = function ADDR_UNIX _ -> failwith "INET socket expected" |ADDR_INET(cl_inet_addr,_) -> (gethostbyaddr cl_inet_addr).h_name ;; (* == val message : string -> string -> string *) (* Compose le message de reponse a la connection d'un client *) let message cl_addr n_con = Printf.sprintf "Hello %s (%s)\n" cl_addr n_con ;; (* == val write_log : string -> unit *) (* Ecriture d'une ligne dans le fichier trace *) let write_log s = let f = open_out_gen [Open_wronly;Open_text;Open_append; Open_creat] (6*64+4*8+4) "hello.log" in output_string f s; close_out f ;; (* == val con_line : string -> Unix.tm -> string -> string *) (* Construction d'une ligne pour le fichier trace : *) (* Demande de connexion : nom-client date heure numero *) let con_line cl_name t_con n_con = Printf.sprintf "%s connection %d/%d/%d %d:%d:%d (%s)\n" cl_name t_con.tm_mday t_con.tm_mon t_con.tm_year t_con.tm_hour t_con.tm_min t_con.tm_sec n_con ;; (* == val ack_line : string -> Unix.tm -> Unix.tm -> string -> string *) (* Construction d'une ligne pour le fichier trace : *) (* Acquitement : *) (* nom-client date heure date-demande heure-demande numero-demande *) let ack_line cl_name t_ack t_con n_con = Printf.sprintf "%s acknoledgement %d/%d/%d %d:%d:%d [%d/%d/%d %d:%d:%d (%s) request] \n" cl_name t_ack.tm_mday t_ack.tm_mon t_ack.tm_year t_ack.tm_hour t_ack.tm_min t_ack.tm_sec t_con.tm_mday t_con.tm_mon t_con.tm_year t_con.tm_hour t_con.tm_min t_con.tm_sec n_con ;; (* == val mk_n_con : float -> string *) (* Construction d'un numero de demande de connexion (decimales du *) (* temps systeme *) let mk_n_con t = let t = string_of_float t in let i = String.index t '.' in let l = (String.length t)-i-1 in String.sub t (i+1) l ;; (* == val server : unit -> unit *) (* Le serveur *) let server () = (* Si pas d'argument : erreur *) if Array.length Sys.argv < 2 then begin Printf.eprintf "Usage : hello3d portnumber\n" end (* sinon *) else (* Lecture du numero de port du service *) let port = get_s_port Sys.argv.(1) in (* Creation de la socket de service *) let sock = socket PF_INET SOCK_STREAM 0 in (* Adresse du serveur *) let h_addr = (gethostbyname (gethostname())).h_addr_list.(0) in let sock_addr = ADDR_INET(h_addr, port) in let sock_addr = ADDR_INET(h_addr, port) in begin (* Liaison socket/adresse *) bind sock sock_addr; (* Mise en attente de connection *) listen sock 5; (* Boucle de service *) while true do (* On accepte une connexion *) let (cl_sock, cl_sock_addr) = accept sock in (* On cree un processus de traitement de la connexion (le fils) *) if fork() == 0 then begin (* Hack Unix :-) *) if fork()<>0 then exit 0; (* Nom du client *) let cl_name = get_cl_name cl_sock_addr in (* Temps (systeme) de connexion *) let t_con = Unix.gettimeofday() in (* Numero de connexion *) let n_con = mk_n_con t_con in (* Date locale de connexion *) let t_con = Unix.localtime t_con in (* Emmission de message reponse *) (let m = message cl_name n_con in write cl_sock m 0 (String.length m)); (* Ecriture trace connexion *) write_log (con_line cl_name t_con n_con); (* Lecture de l'acquitement *) (let r = String.make 2 '\000' in read cl_sock r 0 2); (* Ecriture trace acquittement *) (let t_ack = Unix.localtime(Unix.gettimeofday()) in write_log (ack_line cl_name t_ack t_con n_con)); (* Fermeture de la socket client *) close cl_sock; (* Fin du processus de traitement de connexion *) exit 0 end else (* Le pere *) (* Attente fin de traitement connexion (par le fils) *) let _ = wait() in close cl_sock done end ;; (* == Programme principal *) try server() with Unix_error(c,f,x) -> Printf.eprintf "\n %s in %s %s\n" (error_message c) f x |Failure x -> Printf.eprintf "\n %s \n" x ;;
Page initiale Maison Page précédente POD