BAB III PEMBAHASAN
3.1 Perancangan secara umum Program ini terdiri dari dua aplikasi, yaitu aplikasi client yang diinstall pada setiap client yang ingin saling berhubungan dan aplikasi server yang menangani semua permintaan client.
3.2 Proses Pembuatan Aplikasi Messenger
Aplikasi messenger ini terdiri dari lima file yaitu server.erl, client.erl, mess_client.erl, config.hrl, dan interface.hrl. Untuk aplikasi server menggunakan file config.hrl dan server.erl sedangkan untuk aplikasi client menggunakan file config.erl, client.erl, mess_client, dan interface.hrl. Diasumsikan aplikasi server dan client diinstal pada komputer yang berbeda. Erlang mempunyai standar mekanisme keamanan untuk mencegah akses yang tidak diinginkan dari komputer lain.
23
24
3.2.2 Proses Pembuatan Aplikasi pada Server Tampilan pada server merupakan tampilan yang diinstal pada computer yang akan menjadi server. Berisi daftar nama user yang logon agar kita dapat melihat siapa saja yang sedang online dan status server apakah sedang berjalan atau tidak. Pada tampilan ini, kita menggunakan tiga file yaitu file config.hrl, interface.hrl dan server.erl. Untuk file config.hrl diisi dengan perintah berikut : File config.hrl -define(server_node, server@supernova).
Perintah di atas untuk mendefinisikan nama node server yang akan digunakan sebagai server. Jadi node pada komputer server diberi nama server, contoh :
Gambar 3.6 Tampilan pemberian nama pada node server
25
Kemudian akan ditampilkan shell erlang seperti gambar berikut ini :
Gambar 3.7 tampilan shell erlang dengan nama node server File selanjutnya yaitu file interface.hrl yang berisi penentuan bentuk format kode yang akan digunakan dalam aplikasi ini. File interface.hrl -record(logon,{client_pid, username}). -record(message,{client_pid, to_name, message}). -record(abort_client,{message}). -record(server_reply,{message}). -record(message_from,{from_name, message}). -record(message_to,{to_name, message}).
26
Digunakan untuk membuat suatu struktur atau format perintah. Sebagai contoh, perintah
-record(logon,{client_pid, username}).
Berfungsi untuk membuat suatu format perintah logon yang harus terdiri dari tuple {client_pid, username} dan isi dari masing-masing elemen pada tuple tersebut harus diisi pada saat digunakan, contoh :
#logon{client_pid=From, username=Name}
Elemen-elemen pada tuple di atas diisi dengan variabel From dan Name
File yang terakhir yaitu file server.erl. Berisi kode yang akan menjalankan aplikasi server. Fasilitas yang ada dalam aplikasi server ini yaitu dapat melihat daftar user yang sedang logon dan status server sudah berjalan atau belum. File server.erl -module(server). -export([start/0, server/0,stop/0]). -include("interface.hrl"). server() -> process_flag(trap_exit, true), server([]). server(User_List) -> Waktu=io_lib:format("~w:~w:~w~n",tuple_to_list(time())),
27
io:format("-> Daftar User yang logon pukul ~s ~p~n~n", [Waktu,User_List]),
User_List),
receive #logon{client_pid=From, username=Name} -> New_User_List = server_logon(From, Name, server(New_User_List); {'EXIT', From, _} -> New_User_List = server_logoff(From,
User_List),
message=Message} -> User_List), end.
server(New_User_List); #message{client_pid=From, to_name=To, server_transfer(From, To, Message, server(User_List)
start() -> case whereis(messenger) of undefined -> io:format("~n############################################### #~n",[]), io:format("################################################~ n",[]), io:format("########### SIMPLE ERLANG MESSENGER ############~n",[]), io:format("########### [ SEM ] 1.0 2006 ############~n",[]), io:format("################################################~ n",[]), io:format("################################################~ n~n",[]), io:format("- note :\'server:start().\' <menjalankan server~n",[]), io:format(" \'server:stop().\' <menghentikan server~n~n",[]), Waktu=io_lib:format("~w:~w:~w~n",tuple_to_list(time())), io:format("-> Dimulai pukul ~s ~n~n",[Waktu]),
28
io:format("-> server status [ running ]~n~n",[]), start_1(); _ -> io:format("~n~n<<-------- Server sedang berjalan ------->>~n~n",[]) end. start_1() -> register(messenger, spawn(?MODULE, server, [])).
stop() -> case whereis(messenger) of undefined -> io:format("~n~n<<-------------------- Server belum dijalankan -------------------->> ~n",[]), io:format("<<----- Jalankan dengan menggunakan perintah server:start() ------->>~n~n",[]), exit(normal); _ -> Waktu=io_lib:format("~w:~w:~w~n",tuple_to_list(time())), io:format("~n~n-> stop server sukses ]~n",[]), io:format("-> stop pukul ~s ~n",[Waktu]), io:format("-> server status [ stop ]~n",[]),unregister(messenger)
[
end.
server_logon(From, Name, User_List) -> case lists:keymember(Name, 2, User_List) of true -> From ! #abort_client{message="<<---- sudah ada yang menggunakan user tersebut ---->>"}, User_List; false -> From ! #server_reply{message="<< Logon sukses -- ketik client:help(). untuk melihat daftar perintah >>"}, link(From), [{From, Name} | User_List] end.
29
server_logoff(From, User_List) -> lists:keydelete(From, 1, User_List). server_transfer(From, To, Message, User_List) -> case lists:keysearch(From, 1, User_List) of false -> From ! #abort_client{message="<<---- Anda belum login ---->>"}; {value, {_, Name}} -> server_transfer(From, Name, To, Message, User_List) end. server_transfer(From, Name, To, Message, User_List) -> case lists:keysearch(To, 2, User_List) of false -> From ! #server_reply{message="<<---- penerima tidak dapat ditemukan ---->>"}; {value, {ToPid, To}} -> ToPid ! #message_from{from_name=Name, message=Message}, From ! #server_reply{message="<<---- pesan terkirim --->>"} end.
Penjelasan program :
Program dimulai ketika pada shell diketikkan perintah server:start() Setelah itu program akan memanggil fungsi start() yang berisi
start() -> case whereis(messenger) of undefined -> io:format("~n############################################### #~n",[]), io:format("################################################~ n",[]),
30
io:format("########### SIMPLE ERLANG MESSENGER ############~n",[]), io:format("########### [ SEM ] 1.0 2006 ############~n",[]), io:format("################################################~ n",[]), io:format("################################################~ n~n",[]), io:format("- note :\'server:start().\' <menjalankan server~n",[]), io:format(" \'server:stop().\' <menghentikan server~n~n",[]), Waktu=io_lib:format("~w:~w:~w~n",tuple_to_list(time())), io:format("-> Dimulai pukul ~s ~n~n",[Waktu]), io:format("-> server status [ running ]~n~n",[]), start_1(); _ -> io:format("~n~n<<-------- Server sedang berjalan ------->>~n~n",[]) end.
Pertama kali program akan mengecek proses yang bernama “messenger” dengan perintah : case whereis(messenger) of undefined ->
apabila proses yang bernama “messenger” belum didefinisikan atau undefined maka perintah di bawahnya akan dijalankan yaitu mencetak tampilan awal program dan memanggil fungsi start_1().
31
Gambar 3.7a Tampilan Server
Apabila proses “messenger” sudah terdefinisi maka program akan menjalankan perintah : _ -> io:format("~n~n<<-------- Server sedang berjalan ------->>~n~n",[])
32
Gambar 3.7b Tampilan server yang sudah dijalankan sebelumnya
Pada fungsi start_1() program akan menjalankan kode yang berfungsi untuk mendefinisikan suatu proses bernama “messenger” dan menjalankan modul server dengan fungsi server() melalui perintah :
start_1() -> register(messenger, spawn(?MODULE, server, [])).
?MODULE disini akan diganti dengan nama module di mana kode ini berada atau seperti yang sudah didefinisikan pada perintah :
33
-module(server).
Dalam kasus ini akan diganti dengan “server”.
Ketika fungsi server dipanggil, fungsi tersebut akan menjalankan kode :
server() -> process_flag(trap_exit, true), server([]).
Yang berfungsi untuk menangkap pesan dari proses yang mengalami error atau terhenti secara tidak normal dan juga user yang keluar tanpa melakukan logout. Kemudian program akan segera mengupdate daftar user yang sedang logon.
Setelah itu fungsi server(User_List) akan menerima pesan dengan format
[{ClientPid1, Name1},{ClientPid22, Name2},...]
server(User_List) -> Waktu=io_lib:format("~w:~w:~w~n",tuple_to_list(time())), io:format("-> Daftar User yang logon pukul ~s ~p~n~n", [Waktu,User_List]),
User_List),
receive #logon{client_pid=From, username=Name} -> New_User_List = server_logon(From, Name,
34
server(New_User_List); {'EXIT', From, _} -> New_User_List = server_logoff(From,
User_List),
message=Message} -> User_List), end.
server(New_User_List); #message{client_pid=From, to_name=To, server_transfer(From, To, Message, server(User_List)
Apabila format tersebut diterima maka program akan menjalankan fungsi server_logon(From,User_list) yang akan mendaftarkan user yang mengirim pesan tersebut.
Gambar 3.8 Tampilan user yang sudah terdaftar
35
Jika pesan yang diterima berformat
{'EXIT', From, _}
Maka program akan memanggil fungsi
server_logoff(From, User_List)
yang akan menghapus proses yang mengirimkan pesan tersebut dari daftar user yang logon. Dan apabila yang diterima berformat
#message{client_pid=From, to_name=To, message=Message}
Maka program akan memanggil fungsi server_transfer(From, To, Message, User_List)
yang berfungsi untuk mengirimkan pesan berupa teks yang digunakan user untuk berhubungan satu sama lain bukan pesan antar proses ke tujuan.
Yang terakhir yaitu fungsi stop() yang berguna untuk menghentikan aplikasi server. Dijalankan dengan menggunakan perintah server:stop().pada shell erlang.
36
Gambar 3.9 Tampilan stop server
3.2.3 Proses Pembuatan Aplikasi pada Client Aplikasi pada client terdiri dari empat file yaitu, config.hrl, interface.hrl, mess_client.erl dan client.erl. Berikut akan dijelaskan fungsi masing-masing file yang digunakan pada aplikasi client. File config.hrl :
-define(server_node, server@supernova).
37
Untuk penjelasannya sama seperti yang sudah dibahas pada proses pembuatan aplikasi pada server dan berlaku juga untuk file interface.hrl File interface.hrl -record(logon,{client_pid, username}). -record(message,{client_pid, to_name, message}). -record(abort_client,{message}). -record(server_reply,{message}). -record(message_from,{from_name, message}). -record(message_to,{to_name, message}).
Berikutnya yaitu file client.erl. File ini merupakan file yang berhubungan langsung dengan user. File client.erl : -module(client). -export([logon/1, logoff/0, message/2,help/0]). -include("interface.hrl"). -include("config.hrl"). logon(Name) -> case whereis(mess_client) of undefined -> register(mess_client, spawn(mess_client, client, [?server_node, Name])); _ -> io:format("~n<<---- anda sedang login ---->>~n",[]) end. logoff() -> case whereis(mess_client) of undefined -> io:format("~n<<---- anda belum login. silakan login terlebih dahulu ---->> ~n",[]); _ -> io:format("~n<<---- anda telah logoff. Terima kasih --->> ~n",[]),mess_client ! logoff end.
message(ToName, Message) ->
38
case whereis(mess_client) of undefined -> io:format("~n<<---- Anda belum login. silakan login terlebih dahulu ---->>~n",[]); _ -> mess_client ! #message_to{to_name=ToName, message=Message} end. help() -> io:format("~n<<----- Berikut ini command-command yang dapat digunakan dalam SEM 1.0 ----->>~n~n",[]), io:format("-------------------------------- Supernova ----------------------------------~n",[]), io:format(" Untuk login : client:logon(Nama).~n~n",[]), io:format(" -contoh login : client:logon(nofa) <-benar~n",[]), io:format(" : client:logon(Nofa) <-salah~n",[]), io:format(" : client:logon(nofa ryan) \\ client:logon(Nofa_ryan) <-- salah~n",[]), io:format("~n dimulai dengan huruf kecil atau satu kata, apabila ingin dengan huruf besar~n",[]), io:format(" ataupun lebih dari satu kata gunakan tanda petik, contoh~n~n",[]), io:format(" -client:logon(\"Ryan\") \\ client:logon(\"Ryan Ganteng\") <-- benar~n~n",[]), io:format("> Melihat node yang lain : nodes(). <-- di akhir harus menggunakan titik \'.\'~n~n",[]), io:format("> Mengirim pesan : client:message(Nama_yg_dituju,Pesan).~n~n",[]), io:format(" -note : perintah diatas berjalan bila \'Nama_yg_dituju\' dan \'Pesan\'~n",[]), io:format(" hanya satu kata juga diawali dengan huruf kecil. Jika ingin lebih~n",[]), io:format(" dari satu kata gunakan tanda kutip \"\" pada \'Nama_yg_dituju\' dan 'Pesan\'~n~n contoh :",[]), io:format(" client:message(ryan,hallo). <-- benar~n",[]), io:format(" client:message(\"Ryan Ganteng\",\"Haloo apa kabar??\"). <-- benar~n",[]), io:format(" client:message(Ryan ganteng\\ryan ganteng,hai apa kabar\\Hai). <-- salah~n~n",[]), io:format("> Untuk logoff : client:logoff().~n~n",[]), io:format("<<---------------------------- End Of File --------------------------------->>~n",[]).
Penjelasan program :
39
Pertama mendefinisikan nama module, fungsi dan file yang diinclude dengan perintah : -module(client). -export([logon/1, logoff/0, message/2,help/0]). -include("interface.hrl"). -include("config.hrl").
Kemudian fungsi logon(Name),logoff(), message(To,Message) ataupun help() akan dijalankan apabila user memanggil atau menjalankan fungsi tersebut, sebagai contoh user yang akan logon menggunakan fungsi logon(Name). Pemanggilan fungsi tersebut diinput pada shell erlang dengan format : nama_file/modul:nm_fungsi(argumen). Dalam kasus ini client:logon(ryan). Setelah dijalankan fungsi logon() akan mengecek apakah proses yang bernama “mess_client” sedang berjalan atau tidak dengan perintah :
case whereis(mess_client) of undefined -> register(mess_client, spawn(mess_client, client, [?server_node, Name])); _ -> io:format("~n<<---- anda sedang login ---->>~n",[]) end.
40
Apabila tidak ditemukan maka fungsi logon() akan membuat/mendaftarkan proses yang bernama “mess_client” yang merupakan nama dari pembuatan proses pada file “mess_client.erl “ yang memanggil fungsi client() dengan argumen [?server_node, Name] ?server_node akan diganti dengan “server@supernova” sesuai yang telah didefinisikan pada file config.hrl. Sedangkan untuk “Name” akan diganti sesuai variabel “Name” yang diinput oleh user dalam kasus ini “ryan”. Selain dari kondisi tersebut fungsi akan mencetak kalimat “anda sedang login” pada shell erlang. Fungsi logoff() berfungsi untuk logout dari aplikasi messenger. logoff() -> case whereis(mess_client) of undefined -> io:format("~n<<---- anda belum login. silakan login terlebih dahulu ---->> ~n",[]); _ -> io:format("~n<<---- anda telah logoff. Terima kasih --->> ~n",[]),mess_client ! logoff end.
Pertama fungsi akan mengecek apakah proses “mess_client” sudah berjalan atau didefinisikan sebelumnya, apabila sudah maka fungsi akan mengirim pesan atom logoff ke proses “mess_client” dan program akan berhenti. Selain dari itu program akan mencetak kalimat “anda belum login.....” pada shell erlang.
41
Fungsi message(ToName, Message) -> case whereis(mess_client) of undefined -> io:format("~n<<---- Anda belum login. silakan login terlebih dahulu ---->>~n",[]); _ -> mess_client ! #message_to{to_name=ToName, message=Message} end.
Befungsi untuk mengirimkan pesan antar user. Untuk mengirim pesan antar user digunakan perintah :
client:message(tujuan, pesannya).
pada shell erlang, sebagai contoh kita akan mengerim pesan “hallo” untuk user yang bernama “ryan” :
client:message(ryan,hallo).
Pada saat fungsi ini dipanggil seperti biasa fungsi akan memeriksa terlebih dahulu apakah proses “mess_client" sudah berjalan atau belum. Apabila belum maka program akan mencetak kalimat “Anda belum login......” pada shell selain dari kondisi itu fungsi akan mengirimkan format pesan yang sebelumnya didefinisikan pada file interface.hrl ke proses client yaitu :
42
_ -> mess_client ! #message_to{to_name=ToName, message=Message}
client:message(ryan,hallo). Akan menjadi ,
#message_to{to_name=ryan, message=hallo}
Yang terakhir yaitu fungsi help() yang berfungsi sebagai petunjuk cara penggunan aplikasi Simple Erlang Messenger ini. help() -> io:format("~n<<----- Berikut ini command-command yang dapat digunakan dalam SEM 1.0 ----->>~n~n",[]), io:format("-------------------------------- Supernova ----------------------------------~n",[]), io:format(" Untuk login : client:logon(Nama).~n~n",[]), io:format(" -contoh login : client:logon(nofa) <-benar~n",[]), io:format(" : client:logon(Nofa) <-salah~n",[]), io:format(" : client:logon(nofa ryan) \\ client:logon(Nofa_ryan) <-- salah~n",[]), io:format("~n dimulai dengan huruf kecil atau satu kata, apabila ingin dengan huruf besar~n",[]), io:format(" ataupun lebih dari satu kata gunakan tanda petik, contoh~n~n",[]), io:format(" -client:logon(\"Ryan\") \\ client:logon(\"Ryan Ganteng\") <-- benar~n~n",[]), io:format("> Melihat node yang lain : nodes(). <-- di akhir harus menggunakan titik \'.\'~n~n",[]), io:format("> Mengirim pesan : client:message(Nama_yg_dituju,Pesan).~n~n",[]), io:format(" -note : perintah diatas berjalan bila \'Nama_yg_dituju\' dan \'Pesan\'~n",[]), io:format(" hanya satu kata juga diawali dengan huruf kecil. Jika ingin lebih~n",[]), io:format(" dari satu kata gunakan tanda kutip \"\" pada \'Nama_yg_dituju\' dan 'Pesan\'~n~n contoh :",[]), io:format(" client:message(ryan,hallo). <-- benar~n",[]), io:format(" client:message(\"Ryan Ganteng\",\"Haloo apa kabar??\"). <-- benar~n",[]),
43
io:format(" client:message(Ryan ganteng\\ryan ganteng,hai apa kabar\\Hai). <-- salah~n~n",[]), io:format("> Untuk logoff : client:logoff().~n~n",[]), io:format("<<---------------------------- End Of File --------------------------------->>~n",[]).
File yang terakhir adalah file mess_client.erl. File yang berfungsi sebagai penghubung antara client dan server.
File mess_client.erl : -module(mess_client). -export([client/2]). -include("interface.hrl"). client(Server_Node, Name) -> {messenger, Server_Node} ! #logon{client_pid=self(), username=Name}, await_result(), client(Server_Node). client(Server_Node) -> receive logoff -> exit(normal); #message_to{to_name=ToName, message=Message} -> {messenger, Server_Node} ! #message{client_pid=self(), to_name=ToName, message=Message}, await_result(); {message_from, FromName, Message} -> io:format("Pesan dari ~p: ~p~n", [FromName, Message]) end, client(Server_Node). await_result() -> receive #abort_client{message=Why} -> io:format("~p~n", [Why]), exit(normal); #server_reply{message=What} -> io:format("~p~n", [What]) after 5000 ->
44
end.
io:format("Tidak ada respon dari server~n", []), exit(timeout)
Penjelasan program : Pada file client.erl fungsi client(Server_Node, Name) telah dipanggil sehingga secara otomatis proses “mess_client” ini telah berjalan. Pertama fungsi client(Server_Node, Name) akan menerima pesan dari proses client berupa Atom “server@supernova” dan “ryan’ masing-masing akan dimasukkan kedalam variabel Server_Node dan name. Kemudian “mess_client” akan mengirim pesan dengan format
{messenger, Server_Node} ! #logon{client_pid=self(), username=Name}, await_result(), client(Server_Node).
Dimana variabel Server_Node diisi dengan atom “server@supernova” dan variabel Name akan diisi dengan atom “ryan”. Yang berarti proses “mess_client” akan mengirim pesan ke proses yang berjalan pada node “server@supernova” berupa format
#logon{client_pid=self(), username=ryan},
45
Lalu fungsi akan memanggil fungsi await_result() yang berfungsi untuk menerima balasan dari server, yaitu : await_result() -> receive #abort_client{message=Why} -> io:format("~p~n", [Why]), exit(normal); #server_reply{message=What} -> io:format("~p~n", [What]) after 5000 -> io:format("Tidak ada respon dari server~n", []), exit(timeout) end.
Apabila yang diterima dari server berformat
#abort_client{message=Why}
Maka program akan mencetak alasan kenapa logon atau pengiriman pesan ke user lain tidak berhasil sebagai contoh sudah ada yang menggunakan nama “ryan”.
46
Gambar 4.0a Tampilan Konfirmasi “Sudah ada yang menggunakan user tersebut”
Bila yang diterima berformat #server_reply{message=What} -> io:format("~p~n", [What])
Ada dua kemungkinan balasan berupa atom ‘pesan terkirim’ atau ‘penerima tidak dapat ditemukan’
47
Gambar 4.0b Tampilan Konfirmasi “Penerima tidak dapat ditemukan”
48
Gambar 4.0c Tampilan Konfirmasi “Penerima Tidak dapat ditemukan”
Yang terakhir bila tidak ada balasan dalam rentan waktu 5000 ms maka program akan mencetak kalimat “tidak ada respon dari server”.
49
Gambar 4.0d Tampilan Konfirmasi “Tidak Ada respon dari server”