Anda di halaman 1dari 16

Tutorial 2

MultiThreaded Server
Tujuan: - Mahasiswa mengerti konsep thread dan mampu membuat aplikasi multithread sederhana - Mahasiswa mampu membuat aplikasi server yang dapat menangani multiple client secara konkuren.

Universitas Atma Jaya Yogyakarta Fakultas Teknologi Industri Teknik Informatika Kusnadi@mail.uajy.ac.id

A. Konsep Pemrograman Thread


Program dengan satu alur eksekusi disebut dengan program sekuensial. Program yang demikian hanya memiliki satu titik eksekusi pada tiap saat. Sedangkan program yang memiliki lebih dari satu alur eksekusi pada tiap saat disebut dengan program konkuren. Tiap unit alur eksekusi dari program konkuren disebut dengan thread. Thread dapat menciptakan thread baru lainnya ataupun membunuh thread yang sudah ada. Thread memberikan ilusi adanya sejumlah aktivitas yang berjalan pada saat bersamaan. Namun bedanya dengan sejumlah proses yang berjalan pada sistem operasi, threadthread yang berjalan pada satu aplikasi memiliki ruang alamat yang sama. Artinya threadthread tersebut memiliki akses bersama ke kode program, memori dan data global yang sama seperti pada gambar 2. Selain struktur data bersama yang dapat diakses bersama, thread juga memiliki struktur data private atau khusus (variabel lokal thread) yang disimpan pada stack thread dan hanya dapat diakses oleh thread bersangkutan.

Kode program Data global Memori (heap) Gambar 1. Program sekuensial Kode program Data global Memori (heap) Stack

Stack Thread 3 Stack Thread 2 Stack Thread 1

Gambar 2. Program Konkuren Keuntungan menggunakan sejumlah thread dalam program antara lain: kemampuan melakukan sejumlah tugas secara simultan dan tak bergantung satu sama lain. Misalkan satu thread melakukan penggambaran animasi secara background, sedangkan thread lain menangani inputan user lewat keyboard. Selain itu thread dapat meningkatkan throughput aplikasi, memperbaiki waktu tanggapan (responsiveness) aplikasi dan kemampuan untuk menggunakan sumber daya sistem secara efisien.

B. Membuat Aplikasi MultiThreaded sederhana dengan Java


Java menyediakan dua cara untuk mengimplementasikan thread. Cara pertama adalah membuat kelas yang mengeksten (inheritance) kelas Thread. Cara kedua adalah membuat

kelas yang mengimplementasikan interface Runnable. Cara kedua berguna terutama jika kita hendak menurunkan kelas yang hendak kita buat dari kelas lainnya selain kelas Thread. Java tidak mendukung multiple inheritance, tapi mendukung multiple interface. Perbedaanya adalah obyek yang dibuat dari kelas yang mengimplementasikan interface Runnable haruslah di-casting ke Thread agar dapat memanggil method-method yang ada pada Thread. Sedangkan obyek dari kelas yang mengeksten kelas Thread dapat memanggil method-method Thread secara langsung. Kelas yang mengimplementasikan thread (baik inheritance Thread maupun implementasi interface Runnable) haruslah mendefinisikan method run(). Method inilah yanng sesunguhnya akan dieksekusi sebagai alur eksekusi independen saat obyek thread memanggilkan mehtod start(). Program D2-1 memberikan contoh membuat kelas thread dengan inheritance sedangkan program D2-2 memberikan contoh serupa dengan mengimplementasikan Runnable. Demo D2-1 Salah satu kemungkinan penggunaan soket adalah menciptakan satu thread untuk menunggu inputan dari user dan thread lainnya menunggu data yang dikirim oleh soket komputer lain. Tutorial dibawah ini menggambarkan kemungkinan tersebut walaupun sebatas simulasi.

1. Buatlah program dibawah ini dan simpan sebagai MyThread.java


class MyThread extends Thread{ private String namaThread; public MyThread(String nama) { namaThread=nama; } public void run(){ for(int i=0;i<3;i++){ System.out.println(namaThread+": " + i); try{ Thread.sleep(500); }catch(InterruptedException e){ e.printStackTrace(); } } }

public static void main(String[] argv){ MyThread t1= new MyThread("Read from Socket"); MyThread t2= new MyThread("Read from Keyboard"); t1.start(); t2.start(); } }

2. Lakukan kompilasi dan jalankan program diatas, amati hasilnya


Read Read Read Read Read Read from from from from from from Socket: 0 Keyboard: 0 Socket: 1 Keyboard: 1 Socket: 2 Keyboard: 2

Demo D2-2 Cara lain untuk mengimplementasikan thread adalah dengan membuat suatu kelas yang mengimplemetasikan interface Runnable. Tutorial ini melakukan hal yang sama dengan D2-1, namun dengan menggunakan interface runnable. Perhatikan pada bagian fungsi main, obyek dari kelas yang dibuat haruslah dicasting ke Thread lebih dulu, sebelum method-method Thread (seperti start()) dapat dipanggil 1. Tuliskan program dibawah ini dan simpan sebagai MyThread2.java:
class MyThread2 extends Thread{ private String namaThread; public MyThread2(String nama) { namaThread=nama; } public void run(){ for(int i=0;i<3;i++){ System.out.println(namaThread+": " + i); try{ Thread.sleep(500); }catch(InterruptedException e){ e.printStackTrace(); } } }

public static void main(String[] argv){ MyThread t1= new MyThread("Read from Socket"); MyThread t2= new MyThread("Read from Keyboard"); ((Thread) t1).start(); ((Thread) t2).start(); } }

2.

Lakukan kompilasi dan jalankan program.

Latihan L2-1 Modifikasi program D2-2 sehingga jumlah looping cetak tiap Thread ditentukan dari argumen konstruktornya. Misalnya dapat diset t1 mencetak 3 kali, dan t2 mencetak 10 kali.

C. Sinkronisasi Thread
Demo D2-3 Tutorial ini membuat aplikasi multithread. Kelas SleepingAnimal mengimplementasikan obyek yang memiliki alur eksekusi tersendiri. Setiap obyek dari kelas ini akan memiliki unit eksekusi sendiri setelah method start() nya dipanggil. Konstruktor kelas ini memiliki dua argumen yaitu nama binatang dan waktu tidurnya (dlm ms). Begitu method start() nya di panggil, maka obyek binatang tersebut akan tidur sesuai waktu tidurnya. Setiap kali terbangun, maka obyek binatang tersebut akan memanggil method eating(). Waktu makan tiap obyek binatang adalah 5 ms dan menghabiskan 1 makanan (variabel numOfFood) yang disimpan pada atribut statik kelas SleepingAnimal. Dalam contoh ini, fungsi utama akan membuat dua obyek SleepingAnimal dan menginisialisasi jumlah makanan sebanyak 1000. Tiap detik (1000 ms), program akan mengecek jatah makanan yang tersisa. Program akan berjalan selama 3 detik dan setelah itu program akan menampilkan statistik makan dari tiap obyek binatang.

1. Tuliskan program dibawah ini dan simpan sebagai SleepingAnimal.java:


public class SleepingAnimal extends Thread{ public static int numOfFood; public int numTerbangun; private String animalName; private int sleepTime; public SleepingAnimal(String aName, int tSleep) { animalName=aName; sleepTime=tSleep; numTerbangun=0; } public static { try { void eating()

int sisamakanan=numOfFood; sleep(5); //5ms numOfFood= sisamakanan-1; } catch(Exception e) { e.printStackTrace();

} } public void run(){ while(true) { try{ Thread.sleep(sleepTime); eating(); numTerbangun++; System.out.println(animalName+ " terbangun dan makan"); }catch(InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] argv) throws Exception{ //inisialisasi awal int JumlahMakanan=1000; SleepingAnimal Kucing= new SleepingAnimal("Kucing Betina",15); SleepingAnimal Anjing= new SleepingAnimal("Anjing",40); SleepingAnimal.numOfFood=JumlahMakanan; //kucing dan anjing mulai hidup Kucing.start(); Anjing.start(); //pengawas mulai hidup for(int i=1; i<=3;i++) { Thread.sleep(1000); System.out.println("\n.checking, makananan tinggal=" + SleepingAnimal.numOfFood +"\n\n"); } //mencetak statistik akhir System.out.println("-------------------------------------"); System.out.println("Kucing terbangun : "+ Kucing.numTerbangun+" kali"); System.out.println("Anjing terbangun : "+ Anjing.numTerbangun+" kali"); System.out.println("Total Termakan: "+ (Kucing.numTerbangun + Anjing.numTerbangun)); System.out.println("Sisa makanan : " + SleepingAnimal.numOfFood+ " dari sebelumnya " + JumlahMakanan); System.out.println("-------------------------------------"); System.exit(0); } }

2. Kompilasi dan jalankan program diatas, hasilnya kurang lebih seperti dibawah ini:
Kucing Kucing Anjing Kucing Kucing Anjing Kucing Betina terbangun dan Betina terbangun dan terbangun dan makan Betina terbangun dan Betina terbangun dan terbangun dan makan Betina terbangun dan makan makan makan makan makan

.....checking, makananan tinggal=829

---------------------------------------

Kucing terbangun : 138 kali Anjing terbangun : 65 kali Total Termakan: 203 Sisa makanan : 829 dari sebelumnya 1000 ---------------------------------------

(NB: Hasil statistik akan berbeda pada tiap eksekusi, karean penjadwalan thread ditentukan oleh sistem operasi dan dipengaruhi banyak faktor pada saat eksekusi) Perhatikan baik-baik pada contoh eksekusi diatas, terlihat total termakan (203) dijumlahkan denga sisa makanan(829) adakag 1031 dab tidaklah tepat 1000 (jatah makanan pada kondisi awal). Mengapa hal ini bisa terjadi? Bagaimana tambahan 31 ini dapat terjadi. Ini dikarenakan terjadi race condition saat mengupdate nilai numOfFood pada method eating(). Perhatikan koding pada method tersebut dimulai dengan membaca nilai variabel numOfFood ke variabel lain dan ada tunda waktu sebesar 5 ms, sebelum akhirnya nilai hasil pengurangan disimpan lagi pada variabel numOfFood. Pada program D2-3 sengaja waktu tidur SleepingAnimal dibuat sangat kecil (15 dan 40 ms), sehingga race condition terjadi. Pada saat terjadi race condition, 2 binatang lagi eating(), namun jatah makanan hanya berkurang satu, karena proses pengurangan jatah makanan pada kedua obyek binatang akan saling menimpa. Tentunya koding semacam ini tentunya tidak efisien disini, namun kondisi seperti ini sering terjadi pada penjadwalan thread dan proses pada level prosesor, dimana nilai suatu variabel disalin ke register di prosesor, dan sangat mungkin kemudian prosesor dipindahkan ke proses atau thread lain untuk waktu cukup panjang sebelumnya akhirnya thread yang pertama melanjutkan proses update variabel bersangkutan. Bagaimana kondisi race condition ini dapat diatasi? Solusinya adalah dengan melakukan sinkronisasi. Sinkronisasi terutama dibutuhkan saat sejumlah thread yang berbeda mengakses suatu sumber daya yang sama seperti variable, file, record di basis data maupun device I/O. Sinkronisasi pada java dapat dilakukan pada sebagian kode program maupun pada suatu fungsi. Konsekuensinya adalah jika suatu thread lagi mengeksekusi bagian tersebut, maka thread lain yang juga hendak mengeksekusi bagian tersebut harus menunggu terlebih dulu.

Demo D2-4 1. Untuk melakukan sinkronisasi pada tingkat fungsi, tambahkan keyword synchronized didepan method eating() pada program D2-3 seperti dibawah ini (lihat bagian )
synchronized public static void eating() { //koding lainnya....... }

2. Kompilasi dan jalankan program , amati hasilnya


---------------------------------------

Kucing terbangun : 131 kali Anjing terbangun : 65 kali Total Termakan: 196 Sisa makanan : 804 dari sebelumnya 1000 ---------------------------------------

Sekarang penjumlah total termakan dan sisa makan sudah sama dengan 1000! 3. Cobalah dijalank berkali-kali untuk memastikan penjumlahannya sudah benar-benar valid. 4. Java juga menyediakan sinkronisasi pada level bagian kode seperti dibawah ini
public static void eating() { synchronized(this) { //koding lainnya....... } }

5. Lakukan kompilasi, jalankan program dan amati hasilnya.

D. Koneksi ke HTTP (Web) Server


HTTP (Hyper text Transfer Protocol) merupakan protokol level aplikasi, yang diimplementasikan oleh HTTP server atau web server. Web browser (IE, Netscape, Mozilla, Firefox) mengontak suatu web server dengan memakai protokol HTTP (baca mengirimkan format pesan yang dimengerti oleh web server, yaitu sesuai aturan pesan protokol HTTP). Dan sebagai balasannya HTTP server membalas dengan mengirimkan format pesan (protokol pesan) yang dimengerti oleh web browser yaitu HTML (Hyper Text Markup Language) Layanan apa yang diberikan oleh HTTP server? Pada dasarnya HTTP server merupakan layanan dokumen ataupun informasi. Jadi ketika kita mengetikkan alamat URL http://www.detik.com/berita.html atau //www.detik.com:80/berita.html, maka browser akan membuka koneksi http (port 80 biasanya) ke www.detik.com. Ini sama dengan melakukan perintah $telnet www.detik.com 80. Kemudian browser (ataupun telnet) akan mengirimkan pesan HTTP yaitu : GET /berita.html HTTP/1.0 yang intinya memintakan HTTP Server mengirimkan isi dokumen berita.html yang terletak pada direktori root server (lokasi sesungguhnya dokument ini tergantung konfigurasi HTTP servernya), sedangkan argumen HTTP/1.0 meminta HTTP server mengirimkan juga data header yang berisi informasi tentang server dan dokumen yang dikirim. Selain perintah GET, sejumlah perintah lain yang dapat dimengerti oleh HTTP server adalah POST dan HEAD, namun tutorial ini hanya akan mencoba menggunakan perintah GET saja. Selain itu HTTP server akan memutuskan koneksi begitu mengirim pesan balasan. Hal yang lain yang butuh dipahami mengenai perbedaan mengakses lewat web browser dan telnet adalah web browser begitu menerima data balasan (dalam format teks html) dari HTTP server akan memparsing isi pesan dan memformat tampilan pesan sesuai dengan tag-tag html dalam pesan, sedangkan telnet hanya akan menampilkan pesan mentah yang dikirimkan oleh HTTP server. Contoh data mentah yang dikirim oleh HTTP server dapat dilihat pada D2-5.

Demo D2-5 Tutorial akan mencoba meminta dokumen testing.html yang terletak pada suatu root direktori HTTP server yang beralamat di 192.168.29.9 dengan memakai telnet 1. Lakukan koneksi telnet ke komputer target dengan perintah $telnet 192.168.29.9 80 2. Akan muncul layar kosong, ketik perintah dibawah ini dan tekan tombol enter 2 kali GET /testing.html HTTP/1.0 3. Amati hasil balasan dari HTTP server
HTTP/1.1 200 OK Server: Microsoft-IIS/5.1 X-Powered-By: ASP.NET Date: Thu, 19 Jul 2007 01:28:18 GMT Content-Type: text/html Accept-Ranges: bytes Last-Modified: Thu, 19 Jul 2007 01:01:58 GMT ETag: "1e8c6468a0c9c71:c66" Content-Length: 56 <HTML> <BODY> HALAMAN PERCOBAAN </BODY> </HTML> Connection to host lost.

NB: Bagian pertama adalah header pesan yang memberikan informasi versi protokol HTTP yang didukung oleh server, jenis servernya, jenis dokumen yang diakses, dan panjang pesan. Isi dokumen dimulai dengan tag <HTML>. Perhatikan juga koneksi langsung ditutup begitu pesan diterima. 4. Coba juga melakukan akses dokumen di situs lain seperti http://inf.uaj.ac.id/index.php dengan menggunakan telnet. 5. Coba juga melakukan akses ke dokumen yang tidak ada seperti http://inf.uajy.ac.id/sembarang.html dan lihat pesan balasan apa yang dikirim oleh server Selain mengakses langsung ke HTTP server, koneksi http dapat dilakukan melalui proxy server. Proxy server berfungsi sebagai perantara untuk pengaksesan dokumen di situs internet. Penggunaan proxy server melindungi komputer-komputer lokal LAN terhadap eksploitasi luar, karena bagi komputer di internet, yang mengakses http server adalah proxy server. Jika web browser dikonfigurasi dengan menggunakan proxy server

10

maka yang melakukan koneksi ke http server tujuan bukanlah web browser lagi, namun proxy server. Web browser hanya melakukan koneksi ke proxy server. Proxy server mendukung perintah yang sama dengan HTTP server. Perbedaanya adalah saat mengirimkan pesan GET ke proxy server, maka harus disertakan juga alamat komputer HTTP server yang dituju seperti : GET http://www.detik.com/berita.html . Proxy server yang akan membuka koneksi ke www.detik.com dan mengirimkan pesan GET /berita.html HTTP/1.0. Demo D2-6 1. Lakukan koneksi telnet ke proxy server (sesuai dengan proxy server tempat anda) $telnet 192.168.5.1 8080 2. Akan muncul layar kosong, ketik perintah dibawah ini dan tekan tombol enter 2 kali GET http://www.jogja.com/index.php HTTP/1.0 3. Amati hasilnya
HTTP/1.0 200 OK Date: Thu, 19 Jul 2007 02:13:17 GMT Server: Apache X-Powered-By: PHP/4.4.4 Content-Type: text/html X-Cache: MISS from proxy2.uajy.ac.id X-Cache: MISS from proxy.uajy.ac.id Proxy-Connection: close <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org /TR/html4/loose.dtd"> <html> <head> <title>:: All Info Jogja ::</title> <meta http-e quiv="Content-Type" content="text/html; charset=iso-8859-1"> <meta httpequiv="re fresh" content="0;URL=http://w3.jogja.com/"> </head> <body> </body> </html>

11

E. Membangun Aplikasi HTTP Server sederhana


Salah satu sifat aplikasi server seperti HTTP server adalah kemampuan untuk menangani request dari sejumlah client secara simultan. Konsep penangan komunikasi soket pada HTTP Server ditunjukkan pada gambar 3. HTTP Server membuat soket server yang dapat melakukan listen terhadap permintaa koneksi client. Ketika Client membuat soket dengan memasukan alamat soket listen HTTP server, maka terjadi permintaan koneksi ke port listen tersebut (biasanya port 80). Pada saat permintaan sampai pada sisi server, maka HTTP server akan membuat soket biasa untuk berkomunikasi dan memproses pesan dari client. Soket server yang melakukan listen pada port 80 akan kembali menunggu permintaan koneksi lainnya (misalkan dari client 2). Dengan demikian HTTP server dapat menangani banyak client sekaligus. Perhatikan hanya soket server listen yang butuh diberi nomer port (80) secara eksplisit. Alamat port soket pada sisi client maupun soket yang dibuat oleh HTTP server , atas permintaan koneksi client, sepenuhnya ditentukan secara acak dan otomatis. Selain itu soket yang menangani komunikasi data (pada langkah 3) haruslah dijalankan pada thread yang terpisah dengan thread yang menangani server soket listen port 80. 3 2 Server membuat soket komunikasi HTTP Server Port 80 Komunikasi data (thread terpisah) Client 1 Web Browser 1 minta koneksi ke port 80 Client 2 Web Browser

Gambar 3. Konsep komunikasi soket pada HTTP Server Dalam tutorial D2-7 akan diberikan contoh pembuatan aplikasi HTTP server sederhana. Untuk mengetes aplikasi ini dapat menggunakan web browser biasa maupun menggunakan telnet seperti pada demo D2-5.

12

Demo D2-7 Tutorial ini akan membuat aplikasi HTTP Server sederhana yang hanya memproses pesan GET dari client. Hal yang dilakukan aplikasi ini ini adalah: membuka soket listen pada port 80 dan menunggu koneksi Setiap kali terjadi koneksi membuatkan soket komunikasi untuk client tersebut membuat thread yang terpisah (class Connect) untuk menangani komunikasi datanya. Thread utama akan kembali menuggu koneksi berikutnya. Dokumen-dokumen HTTP server akan diletakkan satu direktori dengan tempat class httpd dijalankan (otomatis sebagai direktori root server). Selain itu aplikasi ini akan mengirim isi dokumen apa adanya. Jadi script-script server tidak akan diproses terlebih dulu Jika tidak ada nama dokumen yang dicantumkan pada dianggap dokumen yang diakses adalah index.html yang ada di direktori root. NB: Pada web server sesungguhnya, lokasi direktori root HTTP server dapat dikonfigurasi. Selain itu script-script server seperti PHP ataupun javascript akan diproses lebih dulu sebelum hasil akhirnya dikirimkan sebagai pesan (format html) ke sisi client (web browser) 1. Buatlah kelas Connect untuk mengimplementasikan thread yang menangani komunikasi client dengan mengetik program dibawah ini dan simpan sebagai Connect.java
import java.net.*; import java.io.*; import java.util.*;

class Connect extends Thread{ Socket client; BufferedReader is; DataOutputStream os; public Connect(Socket s){ client=s; try { is= new BufferedReader( new InputStreamReader(client.getInputStream())); os= new DataOutputStream(client.getOutputStream()); this.start(); }catch(IOException e){ try{ client.close(); }catch(IOException ex){ System.out.println("Error while getting socket streams: " +ex); } } }

13

public void run(){ try{ String request= is.readLine(); System.out.println("Request: " +request); StringTokenizer st= new StringTokenizer(request); if((st.countTokens()>=2) && st.nextToken().equals("GET")){ //memparsing nama dokumennya if((request=st.nextToken()).startsWith("/")) request= request.substring(1); if(request.endsWith("/") || request.equals("")) request= request+"index.html"; File f= new File(request); //baca dokumen dan kirim lewat stream shipDocument(os,f); }else{ try { os.writeBytes("400 Bad Request"); } catch(Exception ex) { ; } } client.close(); } catch(IOException e){ System.out.println("I/O error " + e); }catch(Exception ex){ System.out.println("Exception: "+ ex); } } public static void shipDocument(DataOutputStream out, File f){ try{ DataInputStream in= new DataInputStream(new FileInputStream(f)); int len=(int) f.length(); byte buf[]= new byte[len]; in.readFully(buf); out.writeBytes("HTTP/1.0 200 OK\r\n"); out.writeBytes("Content-Length: "+ buf.length+ "\r\n"); out.writeBytes("Content-Type: text\\html\r\n\r\n"); out.write(buf); out.flush(); in.close(); }catch(FileNotFoundException e){ try { out.writeBytes("404 Not Found"); } catch(Exception ei) {; } }catch(IOException ex){ System.out.println("Error writing ..."+ex); } } }

14

2. Selanjutnya buatlah kelas layanan HTTP server dengan menulis kode dibawah ini dan simpan sebagai httpd.java;
import java.net.*; import java.io.*; public class httpd extends Thread{ public static final int HTTP_PORT=8080; protected ServerSocket listen; public httpd(){ try{ listen=new ServerSocket(HTTP_PORT); }catch(IOException ex){ System.out.println("Exception..."+ex); } this.start(); } public void run() { try{ while(true){ Socket client=listen.accept(); Connect cc= new Connect(client); } }catch(IOException e){ System.out.println("Exception..."+e); } } public static void main(String argv[]) throws IOException{ new httpd(); } }

3. Pastikan httpd.java dan Connect.java berada pada satu direktori. Kemudian lakukan kompilasi pada httpd.java dan jalankan. (Program akan terus hidup menunggu koneksi client)
$ javac httpd.java $ java httpd

4. Buat atau salinlah sejumlah dokumen html ke lokasi direktori httpd.class. Pastikan salah satu dokumen bernama index.html 5. Bukalah browser dan ketikan alamat url dengan format htttp://<computer lokal>:8080/<nama dokumen> misalkan komputer lokal bernama station dan IP=192.168.29.77 maka dapat dicoba http://127.0.0.1:8080/index.html http://station:8080/index.html http://192.168.29.77/index.html

15

Project P2-1 Buatlah aplikasi Telnet server dan telnet Client. Telnet server beroperasi pada port 2121. Pada dasarnya telnet server menerima pesan dari client dari menjalankan pesan tersebut sebagai perintah shell pada komputer lokal. Output dari shell di tampilan (standard ouput maupun standard error shell) ditangkap oleh telnet server dan dikirim balik ke sisi client (termasuk prompt user). Bagi pengguna telnet client dia seakan-akan berada pada komputer server dan menjalankan shell di server.

16

Anda mungkin juga menyukai