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 Üretici-
Tü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.
Herhangi
bir
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.
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 = 42
Enter message ('0' to exit): 1
PUSHED ITEM = 57
SERVER> YOU POPED = 69
PUSHED ITEM = 85
PUSHED ITEM = 97
Enter message ('0' to exit): 1
PUSHED ITEM = 69
SERVER> YOU POPED = 74
STACK IS FULL
Enter message ('0' to exit): 1
New client accepted.
SERVER> YOU POPED = 41
POPED ITEM = 69
Enter message ('0' to exit): 1
PUSHED ITEM = 74
SERVER> YOU POPED = 16
POPED ITEM = 74
PUSHED ITEM = 41
Enter message ('0' to exit): 1
STACK IS FULL
SERVER> YOU POPED = 97
POPED ITEM = 41
PUSHED ITEM = 16
Enter message ('0' to exit): 1
POPED ITEM = 16
SERVER> YOU POPED = 85
POPED ITEM = 97
POPED ITEM = 85
Enter message ('0' to exit): 1
POPED ITEM = 57
SERVER> YOU POPED = 57
PUSHED ITEM = 70
POPED ITEM = 70
Enter message ('0' to exit): 1
POPED ITEM = 42
SERVER> YOU POPED = 70
STACK IS EMPTY
PUSHED ITEM = 12
Enter message ('0' to exit): 1
POPED ITEM = 12
SERVER> YOU POPED = 42
PUSHED ITEM = 34
PUSHED ITEM = 1
Enter message ('0' to exit): 1
PUSHED ITEM = 85
SERVER> YOU POPED = 12
PUSHED ITEM = 34
PUSHED ITEM = 55
Enter message ('0' to exit): 0
STACK IS FULL
SERVER> Connection closed...
Closing down connection...
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
, take
One()
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
Dostları ilə paylaş: |