Soket Programlama

advertisement
KARADENİZ TEKNİK ÜNİVERSİTESİ
BİLGİSAYAR MÜHENDİSLİĞİ BÖLÜMÜ
BİLGİSAYAR AĞLARI LABORATUARI
Soket Programlama
1. Giriş
JAVA dili süreçler arası iletişim için TCP ve UDP olmak üzere iki farklı soket yapısı
kullanır. Her iki soket yapısı da haberleşmede İstemci-Sunucu (Client-Server) mimarisini
kullanır. Bu deneyde, istemci-sunucu soket setlemeleri ve çoklu kullanım (multithreading)
konularından bahsedildikten sonra TCP yapısına göre bir soket uygulaması üzerinde ÜreticiTüketici (Producer-Consumer) probleminin çok iş parçacıklı (thread) çözümü üretilen kaynak
yığına (stack) itilerek, tüketilen de yığından çekilerek gerçeklenecektir.
2. Server Soket Setlemeleri
Server Soket setleme adımları aşağıda verilmiştir:
 ServerSocket nesnesi türetme: servSock isimli ServerSocket nesnesi özel amaçlar
için ayrılmış numaraların dışında, yani 1024-65535 arası bir port numarası seçerek
aşağıdaki gibi oluşturulur:
ServerSocket servSock = new ServerSocket(2861);
 Sunucuyu bekleme konumuna getirme: servSoc, ServerSocket sınıfına ait
accept() metodunu kullanarak herhangi bir istemcinin bağlanmasını bekler. Bağlantı
kurulduğunda link soket nesnesi şu şekilde türetilir:
Socket link = servSock.accept();
 Yollanacak ve alınacak veriler için giriş/çıkış (input/output) katar (stream)
Setleme: İstemci bilgisayarlardan gelecek mesajları almak ve onlara mesaj göndermek
için Socket sınıfına ait getInputStream ve getOutputStream metodları kullanılarak
input ve output isimli stream nesneleri aşağıdaki gibi türetilir:
Scanner input = new Scanner(link.getInputStream());
PrintWriter output = new PrintWriter(link.getOutputStream(), true);
 Veri Gönderme ve Alma: Soket ile veri gönderme ve alma işlemleri için sırasıyla
println() ve nextLine() metodları kullanılır:
output.println(“Gönderilecek karakter dizisi”);
String message = input.nextLine();
 Soket bağlantısını sonlandırma: Bağlantı Socket nesnesinin close() metodu ile
aşağıdaki şekilde sonlandırılır:
link.close();
3. İstemci Soket Setlemeleri
Sunucu ile bağlantı kurma dışında istemci soket setlemeleri yukarıda sunucu için
anlatılanlarla aynıdır. Sunucu ile bağlantı kurmak için link soket nesnesi sunucunun ismi (veya
IP adresi) ve port numarası parametreleri yardımıyla aşağıdaki gibi türetilir:
Socket link = new Socket(“SunucuAdı” , 2861);
4. İstemci-Sunucu Uygulaması
Kaynak kodlardan Soket klasöründe basit bir istemci-sunucu uygulaması verilmiştir
(Tek istemci ve tek sunucu olacak şekilde çalışmaktadır). Uygulama test edilirken öncelikle
TCPServer.java programı koşularak sunucu başlatılır. Daha sonra TCPClient.java
koşularak istemci çalıştırılır ve sunucu ile bağlantı kurulur. Bu uygulamada istemci tarafından
gönderilen mesajlar sunucu tarafından sayılır ve istemciden “BYE BYE” mesajı geldiğinde
bağlantı sonlandırılırken toplam mesaj sayısı yazılır. Örnek bir program çıktısı aşağıdaki
gibidir:
SERVER
CLIENT
[0] Waiting for connection...
[1] Connected to Server
[3] Received Message : Merhaba
[2] Enter message : Merhaba
[5] Received Message : Nasılsın
[4] Enter message : Nasılsın
[7] Because of Received Message: BYE BYE
* Closing connection... *
[6] Enter message : BYE BYE
[8] SERVER > 3 messages received.
* Closing connection... *
5. Çok İstemcili Tek Sunucu Kullanımı
Sunucu bilgisayara 1‘den fazla istemci bilgisayarın bağlantı kurması durumunda
sunucuda, her bir istemci için yeni bir is parçacığı başlatılmalıdır. Bunun için öncelikle Thread
sınıfı miraslanarak bir thread nesnesi türetilir. Start() metodu ile bu iş parçacığının yapacağı
işin kodunu barındıran run() metodu çağrılır. Çok sayıda iş parçacığı aynı anda koşarken
birbirlerine zaman ayırmaları için sleep() metodu kullanılır ve parametre olarak aldığı
milisaniye kadar askıda durur.
Kaynak kodlardan Multithreading klasöründe, biri ekrana 5 kere “Hello” diğeri de
0-4 arası sayıları yazan iki iş parçacığını çağıran ThreadHelloCount adlı java programı için
örnek çıktı aşağıda verilmiştir:
Hello!
0
1
Hello!
2
3
Hello!
Hello!
4
Yukarıdaki program çıktısına dikkat edilirse iş parçacıkları farklı sıklıklarla çağrılmıştır.
Bunun nedeni sleep() metodundaki Math.random()*1000 ifadesidir. Böylece random
fanksiyonu ile her bir iş parçacığı 0-1 saniye arasında değişen farklı sürelerde askıda
durmaktadır. Dolayısıyla ThreadHelloCount.java adlı program her koşuşunda farklı bir çıktı
üretecektir.
Kaynak kodlardan Multithreading klasöründe daha önce anlatılan soket
uygulamasının çok iş parçacıklı uygulaması verilmiştir. MultiServer.java programında,
Thread sınıfını miraslayan ClientHandler sınıfı herbir Client bağlantısında bir iş parçacığı
başlatmaktadır. MultiClient.java programı soket uygulamasındaki TCPClient.java ile
hemen hemen aynıdır.
6. Senkronize Edilmiş İş parçacıkları
Farklı iş parçacıklarının ortak kullandıkları kaynaklara eşzamanlı erişimleri yanlış
sonuçlar üretmeye neden olabilir. O yüzden ortak kaynaklara eş zamanlı erişimi engelleyecek
bir mekanizmaya ihtiyaç vardır. Java dili bunu synchronized anahtar kelimesi ile
gerçekleştirir. Örneğin aşağıdaki metodda ortak kullanılan sum adlı değişkenin aynı anda farklı
iş parçacıkları tarafından güncellenmemesi için updateSum() adlı metod synchronized
yapılmıştır.
public synchronized void updateSum(int amount)
{
sum += amount;
}
Synchronized bir metodu koşan iş parçacığına o anlık bir iş düşmüyorsa wait()
metodunu çağırarak synchronized metod üzerindeki kilidi kaldırır ve böylece diğer iş
parçacıklarının da ilgili metodu koşmasına izin verir. Eğer bir iş parçacığı işini tamamlamışsa
ve wait() konumundaki başka bir iş parçacığının çalışmasını sağlamak istiyorsa notify()
metodunu kullanır. Wait konumundaki bütün iş parçacıklarının çalıştırılması için de
notifyall() metodu kullanılır. Bu durumda hangi iş parçacığına öncelik verileceğine Java
Virtual Machine (JVM) karar verir.
6.1. Üretici-Tüketici (Producer-Consumer) Probleminin Soketlerle Gerçeklenmesi
Bilindiği gibi üretici-tüketici probleminde üreticinin ürettiği ve tüketicinin tükettiği
kaynak ortak kullanılmaktadır. Burada en önemli problem kaynağa eş zamanlı erişimi
engelleyerek tutarlılığı sağlamaktır. Üretici ve tüketicinin ortak çağırdıkları metodlar
synchronized yapılarak tutarlı bir kaynak güncellemesi yapılabilir.
Üretici-Tüketici uygulaması, kaynak kodlardan Multi Producer-Consumer adlı
klasörün içindedir. Üretici ve tüketicinin ortak erişeceği kaynağı (resourse) üretme ve tüketme
işlerini yapan addOne() ve takeOne() metodları, Resourse.java programı içindedir.
ResourseServer.java programı öncelikle item isimli bir Resourse nesnesi türetir ve
Producer içinde item.addOne() çağrısı ile üretmeye başlar.
istemci
tarafından
sunucuya
bağlantı
kurulduğunda
ResourseServer.java programında handler isimli bir ClientThread threadi başlatılır ve
istemcilerin isteklerine cevap verilir. İstemci, Sunucuya “1” karakteri yolladıkça kaynakları
tutan item nesnesinin takeOne() metodu çağrılarak kaynak harcanır. “0” karakteri ile de
bağlantı sonlandırılır.
Herhangi
bir
addOne() metodunda kaynak üretimi belli bir MAX (5) değerle sınırlandırılmıştır. Bu
değere ulaşıldığında wait() metodu çağrılarak istemcilerin kaynağı tüketmesi beklenir.
Herhangi bir kaynak üretildiğinde tüketilebilmesi için notifyall() metodu ile istemcilere
bilgi verilir. takeOne() metodunda da kaynak bittiğinde (değer 0 olduğunda) wait() metodu
çağrılarak sunucunun kaynak üretmesi beklenir. Herhangi bir kaynak tüketildiğinde
üretilebilmesi için notify() metodu ile sunucuya bilgi verilir.
7. Deney Hazırlığı
1. Socket klasörü içerisindeki TCPServer.java ve TCPClient.java uygulamalarını
çalıştırarak bir istemci ve bir sunucudan oluşan istemci-sunucu uygulamasının nasıl
çalıştığını gözlemleyiniz. Soket nesnesinin nasıl oluşturulduğunu, soket yazma ve soketten
okuma işlemlerinin nasıl gerçekleştirildiğini kavrayınız.
2. Multithreading klasöründeki ThreadHelloCount.java kaynak kodlarında iş
parçacıklarının nasıl oluşturulduğunu ve kullanıldığını kavrayınız. Aynı klasördeki çok
istemci tek sunucu uygulamasını çalıştırarak çok istemciliğin iş parçacıkları ile nasıl
gerçeklendiğini kavrayınız.
3. MultiClient.java programını (Bölüm 6.1’de anlatılan) Multi Producer-Consumer
klasörüne kopyalayıp ismini ConsumerClient.java olarak değiştiriniz ve gerekli
değişiklikleri yaparak Multi Producer-Consumer uygulamasının doğru bir şekilde
çalışmasını sağlayınız. Yazdığınız programı deneye getiriniz.
4. Java programlama dilinde yığın veri yapısının nasıl kullanıldığını Stack klasöründeki
uygulamayı kullanarak kavrayınız. Ayrıca, ilgili dilde rastgele sayı üretiminin nasıl
gerçekleştirileceğini araştırınız.
5. Eclipse, JCreator, Netbeans gibi farklı IDE’leri kullanarak uygulamaları çalıştırabilirsiniz.
Deney sırasında Eclipse kullanılacaktır.
8. Deney Tasarımı ve Uygulaması
1. Deney sorularını cevaplayınız.
2. Deney uygulamalarını aynı makine üzerinde ve ağ ortamında çalıştırınız.
3. Aşağıda detaylı bir şekilde anlatılan üretici-tüketici problemini çok istemci tek sunucu
mimaride gerçekleyiniz.





Resourse.java programı içindeki addOne() ve takeOne() metotlarında gerekli
değişikleri yaparak, 0..99 arası rastgele bir sayı olarak üretilen kaynak yığına itilirken
“PUSHED ITEM = ##”; tüketilen kaynak yığından çekilirken “POPED ITEM = ##”
şeklinde mesaj yazılmasını sağlayınız (Burada ##, 0..99 arası bir sayıdır).
Sunucunun (üretici) yığından çektiği değeri istemciye (tüketici) “YOU POPED = ##”
şeklinde yollaması için gerekli değişiklikleri yapınız.
Yığının dolu veya boş olduğu bilgisini “STACK IS FULL/EMPTY” şeklinde ekrana
yazınız.
Java dilinde yığın veri yapısının nasıl kullanılacağı Stack adlı klasördeki
StackImplement.java isimli kaynak kodda verilmiştir. Herhangi bir programda yığın
veri yapısını kullanmak için java.util.* adlı paket dahil edilmelidir.
İstemciden gelen isteklere (“1” kaynağı tüket emrini, “0” ise uygulamanın sonlanması
emrini verir) bağlı olarak ResourseServer.java ve ConsumerClient.java programlarının
ekran çıktısı aşağıdakine benzer olmalıdır:
ResourseServer
ConsumerClient
PUSHED ITEM =
PUSHED ITEM =
PUSHED ITEM =
PUSHED ITEM =
PUSHED ITEM =
STACK IS FULL
Enter message ('0' to exit): 1
SERVER> YOU POPED = 69
42
57
85
97
69
New client accepted.
POPED ITEM = 69
PUSHED ITEM = 74
POPED ITEM = 74
PUSHED ITEM = 41
STACK IS FULL
POPED ITEM = 41
PUSHED ITEM = 16
POPED ITEM = 16
POPED ITEM = 97
POPED ITEM = 85
POPED ITEM = 57
PUSHED ITEM = 70
POPED ITEM = 70
POPED ITEM = 42
STACK IS EMPTY
PUSHED ITEM = 12
POPED ITEM = 12
PUSHED ITEM = 34
PUSHED ITEM = 1
PUSHED ITEM = 85
PUSHED ITEM = 34
PUSHED ITEM = 55
STACK IS FULL
Closing down connection...
Enter message ('0' to exit): 1
SERVER> YOU POPED = 74
Enter message ('0' to exit): 1
SERVER> YOU POPED = 41
Enter message ('0' to exit): 1
SERVER> YOU POPED = 16
Enter message ('0' to exit): 1
SERVER> YOU POPED = 97
Enter message ('0' to exit): 1
SERVER> YOU POPED = 85
Enter message ('0' to exit): 1
SERVER> YOU POPED = 57
Enter message ('0' to exit): 1
SERVER> YOU POPED = 70
Enter message ('0' to exit): 1
SERVER> YOU POPED = 42
Enter message ('0' to exit): 1
SERVER> YOU POPED = 12
Enter message ('0' to exit): 0
SERVER> Connection closed...
Closing connection...
9. Deney Soruları
1. Soket kavramı, uçtan uca haberleşme ve TCP/UDP kavramlarını açıklayınız.
2. Çok istemcililiğin nasıl gerçeklenebileceğini açıklayınız.
3. addOne() metodundaki notify(); satırı kapatılırsa nasıl bir problemle karşılaşılır?
Producer ve Consumer hangi sırada wait durumuna düşer?
4. takeOne() metodundaki notifyall(); satırı kapatılırsa nasıl bir problemle karşılaşılır?
Producer ve Consumer hangi sırada wait durumuna düşer?
5. Producer, addOne() metodunda hem wait() ile beklerken hem de notifyall() yaparken
istemcilerin kaynağı tüketmesini istiyor. Buradaki wait() ve notifyall() çağrıları
arasındaki fark nedir?
6. Consumer, takeOne() metodunda hem wait() ile beklerken hem de notify() yaparken
sunucunun kaynak üretmesini istiyor. Buradaki wait() ve notify() çağrıları arasındaki
fark nedir?
KARADENİZ TEKNİK ÜNİVERSİTESİ
BİLGİSAYAR MÜHENDİSLİĞİ BÖLÜMÜ
BİLGİSAYAR AĞLARI LABORATUARI
2014-2015 Bahar Dönemi
Soket Programlama Deney Raporu
Grup No:
NUMARA
Ad ve Soyad
1. Deneye Soruları
Deney sorularını el yazısıyla cevaplayınız.
Not: Deney raporu el yazısı ile bu şablon kapak sayfası olacak şekilde hazırlanacaktır. Raporlar,
bir sonraki hafta deneyine kadar teslim edilebilir. Kopya raporlar 0 puan alacaklarını kabul
ederler.
Deney Sorumlusu:
Çağatay Murat Yılmaz
Download