Gönderen Konu: Winsock yardım  (Okunma sayısı 18184 defa)

Winsock yardım

« Yanıtla #30 : 16.02.2010 01:36:34 »
Hızlı düğmeleri aç

tesla

İleti: 426

Çevrimdışı
  • ****
  • Sr. Member
    • Profili Görüntüle
    • http://
Konu başlığı Winsock ama konu yelpazesi baya genişlediği için mesajı buraya atayım dedim. Bu aralar böyle socket programlama ile ilgili bir ödev denk geldi(Java). Grup olarak Fallout'çu olduğumuzdan ordaki Pipboy'dan esinlenerek PipBoy Chater 'diye bir şey yaptık.

Release klasöründeki server ve client ile ufak bir deneme yapabilirsiniz. Kodlar ve ayrıca hızlıca yazılmış ufak bir rapor da içinde, elbet bir CS öğrencisinin işine yarar :)

Server-Client yapısı ile LAN üzerinden mesajlaşmanızı sağlayan ufak bir araç. Bilgisayarların birinde server sürekli açık kalmak durumunda, diğer client'lar server'a bağlanıp, onun üzerinden mesajlaşıyorlar. Mesajlar ödevde öyle  istendiği için UDP kullanıyor o yüzden LAN dışında kullanılırsa baya sakat durumlar oluşabilir :)

Bir de mesajlaşmak için mesela özel mesaj göndermesi için mesajların başına 'P' koyduk, broadcast yapılan mesajlar için 'B' koyduk... gibi. Mesajları etiketledik. Basit olsun bizim olsun diye böyle yaptık ama daha iyi çözümler vardır, farklı mesajları birbirinden nasıl ayırabiliriz?

Winsock yardım

« Yanıtla #31 : 16.02.2010 10:53:12 »
Hızlı düğmeleri aç

skate

İleti: 5.245

A Sinner Scener
Çevrimdışı
  • Administrator
  • *****
  • Hero Member
    • Profili Görüntüle
    • http://www.akaydin.com/
@tesla: Farklı mesajları birbirinden ayırmanın en güzel yolu variable değil de serialized structure göndermekten geçiyor yine.
 
Kod: [Seç]
struct Message {
     int messageType;
     char* message;
}

Sanırım Java'daki karşılığı şöyle birşey oluyor.
 
Kod: [Seç]
class Message {
     public int messageType;
     public String message;
     // constructor v.s. gerekli birşeyler varsa eklenir buraya
}

gibisinden. Zaten bildiğim kadarıyla Java'da Stringler v.s. serializible interfaceinden geliyor, işin C++'a göre daha kolay olacaktır. Class'ı da serializable yapmak gerekiyor. Emin değilim ama "class Message implements Serializable" demek yeterli oluyor olabilir.

Winsock yardım

« Yanıtla #32 : 16.02.2010 15:04:39 »
Hızlı düğmeleri aç

tesla

İleti: 426

Çevrimdışı
  • ****
  • Sr. Member
    • Profili Görüntüle
    • http://
Hmm, anladım. Evet Java serializible'a biraz baktım, Java işi baya kolaylaştırmış. Dediğin gibi "class Message implements Serializable" demen yeterli oluyor ve sonra her türlü I/O işlemi için gönderilebilir hale geliyor. Güzel ;)

Winsock yardım

« Yanıtla #33 : 16.02.2010 18:51:16 »
Hızlı düğmeleri aç

deniz

İleti: 22

Çevrimdışı
  • *
  • Newbie
    • Profili Görüntüle
    • http://www.cizbakalim.com
Java object serialization network den paket gönderirken işe overhead üstüne overhead katıyor. Belki ufak ödevler için kullanılabilir ama düzgün projeler için asla tercih etmemek gerek. Kendi serialization fonksiyonun ile veriyi packed bir biçimde bir data buffer a kopyalamak ve daha sonra bu buffer ı mesaj haline getirip socket den yollamak çok daha güzel olacaktır. Bir tanıdığım network den vector, Hashmap felan yolluyordu serialize edip :) artık siz düşünün gerisini. Bu arada network demişken MINA diyorum ve çekiliyorum: http://mina.apache.org/

Winsock yardım

« Yanıtla #34 : 16.02.2010 19:37:21 »
Hızlı düğmeleri aç

skate

İleti: 5.245

A Sinner Scener
Çevrimdışı
  • Administrator
  • *****
  • Hero Member
    • Profili Görüntüle
    • http://www.akaydin.com/
Bu arada serialization ile ilgili en dikkat edilmesi gereken şey recursive bir biçimde classların içerdiği en alt seviyeye kadar tüm objeleri serialize ve unserialize edebilmesi. Deniz'in tavsiye ettiği gibi kendi serialization class'ını oluşturacaksan, dikkat etmen gereken şey class'ın içinde yer alan diğer class tipleriyle tanımlanmış objeler. Eğer söz konusu class içinde başka bir class geçiyorsa ona da aynısını uygulayacak şekilde en alt seviyedeki native tiplere kadar herşeyi serialize edebilmesi gerekiyor. Bir diğer seçenek ise OOP tasarımdan ödün vererek herşeyi tek bir class'da toplamak. Küçük projeler için sorun olmaz ama ciddi bir işe girişirken tavsiye etmem.

Winsock yardım

« Yanıtla #35 : 17.02.2010 02:07:50 »
Hızlı düğmeleri aç

tesla

İleti: 426

Çevrimdışı
  • ****
  • Sr. Member
    • Profili Görüntüle
    • http://
@deniz
Evet, denemelerde String denemiştim, başına bir kaç byte ekledi fazla önemsememiştim, demekki sonradan baya sıkıntı oluyor bu overhead'ler. Hmm, MINA'nın quickstart'ına baktım kullanımı kolay gibi. Bu arada MINA'nın geliştirici ekibine de bir bakayım dedim, Ersin Er'i gördüm. Hacettepe'den hocam, Apache ile baya ilgiliydi zaten.

@skate
Tam dediğin gibi bir şey oldu. ıçinde AudioClip değişkeni olan bir Class'ı denemek için serialization yapmıştım direk "AudioClip var, serialization yapamazsın" gibi bir hata aldım. Ordan yola çıkaraktan, olur olmaz yerde serialization yapmamak gerek sanırım yada Class'ı mümkün olduğunca sade tutmak gerek.

Hmm, o zaman bizim çözüm gene fena değilmiş hehe :)

Winsock yardım

« Yanıtla #36 : 17.02.2010 03:05:53 »
Hızlı düğmeleri aç

skate

İleti: 5.245

A Sinner Scener
Çevrimdışı
  • Administrator
  • *****
  • Hero Member
    • Profili Görüntüle
    • http://www.akaydin.com/
@tesla: sizin uyguladığınız methodu bir şekilde termonolojiye sokmak gerekirse "fixed length messaging" diyebiliriz. bu da legaldir elbette ki. ancak birkaç dez avantajı var.
 
1) fixed length olması gerektiği için her zaman her bilgi bloğunun mümkün olan en uzun veri kadar yer kaplaması gerekecektir. yani private ya da broadcast için 1 karakterlik alan yeterli olurken mesajdan sonraya bir bilgi eklemek gerekirse olabilecek en uzun mesaj kadar (örneğin 4096 karakter) boşluk bırakmak gerekecektir. yalnızca bir "ok" mesajı için bu oldukça gereksiz elbette ki. göndermeden önce sıkıştırma da yapılabilir elbette ki ancak bu defa da sık gönderilen paketlerde her iki tarafta da gereksiz bir cpu kullanımı yaratacaktır.
2) ikinci sorun bir sonraki bahsedeceğim yöntemle ortak, orada açıklayacağım.
 
"fixed length" kullanmazsak "seperated" kullanmamız gerekir. aslında bu metod bir bakıma serialization'ın ilk adımı sayılabilir. biz burada CSV gibi bir format düşünelim. şimdi boşa yer kaplama derdimiz yok ancak;
 
1) Seperation karakteri dataların içinde geçerse escapelenmeli.
2) şimdi fixed length'de de karşımıza çıkan sorunu burada dile getirelim. Her farklı data paketi için karşı tarafta o pakete özel bir "yorumlayıcı" olmak zorundadır. Paket içeriği değiştikçe de bu fonksiyonların güncellenmesi gerekmektedir. Ayrıca type safety ile ilgili ciddi sıkıntılar çıkabilir.
 
Yani serialization olmadığı durumda farklı paket tipleri çoğaldıkça iş içinden çıkılmaz bir hal alabilir. Daha doğrusu hata çıkma ihtimali çok artar ve unit testlere ağırlık vermek gerekir.
 
Gelelim serialization'ın avantajına. Tüm paket tipleri için tek bir serialize ve unserialize fonksiyonu kullanılabilir, hatta her iki tarafta da (server/client) bu fonksiyonlar ortak olabilir.
 
Benim gördüğüm, tecrübe ettiğim ideal yöntem.
 
Server, client için iki değil toplamda 3 proje olacak. Server, Client ve ikisinin ortak kullanacağı bir dll (ya da kullanılan dildeki derlenmiş kütüphane karşılığı). Server ve Client'ın ortak kullanacağı herşey 3. projede yer alacak. Böylece birşey değiştiği anda her iki projede de otomatik olarak değişmiş olacak. Serialization ile ilgili şeyler de burada yer alabilir.
 
Sanırım hazır birşey kullanmanın haricinde en ağrısız sancısız yöntem bu.
« Son Düzenleme: 17.02.2010 03:07:58 Gönderen: skate »

Winsock yardım

« Yanıtla #37 : 17.02.2010 09:45:20 »
Hızlı düğmeleri aç

deniz

İleti: 22

Çevrimdışı
  • *
  • Newbie
    • Profili Görüntüle
    • http://www.cizbakalim.com
Benim şimdiye kadar farklı projelerde denediğim şu iki yöntem var;

1) Network katmanında Packet gibi bir base class dan türeyen LoginRequestPacket, ChatMessagePacket, XXXPacket gibi alt sınıflar tanımlayıp, her sınıfın kendi içerisinde bir adet serialize() ve bir adet de deserialize() fonksiyonunu overload etmesini sağlamak. Burada datayı (java ile konuşacak olursam) ByteBuffer içerisie yazıyor ya da okuyorum. Veri writeInt(), writeUTF(), writeByte() gibi fonksiyonlar ile gayet sıkışık bir düzende yazılıyor. Yine aynı şekilde de okunuyor. Mesajlar kendi içerisinde kendi uzunluklarını da tutuyorlar, bu şekilde değişken uzunlukta mesajlar gönderebiliyoruz. Örneğin; UserListPacket gibi bir paket içerisinde kullanici_adi, puan ikilileri var diyelim. Tabii o anda sistemde kaç kullanıcı var ise bu paketin boyu da dinamik olarak değişiyor. Deserialize eden fonksiyon paket büyüklüğüne göre okuma işlemini yaptığında bir sorun olmuyor. Bu tarz bir 1mesaj=1paket yaklaşımının güzelliği; network arayüzü gayet açık bir şekilde ortaya konuluyor, kaynaklar (bandwidth) çok verimli kullanılıyor, herşey speclere göre ortada , proje yönetimi gayet mutlu oluyor. Negatif yönü; her küçük mesaj için gidip bir daha sınıf tanımı yapmak bir süre sonra can sıkıcı hale gelebiliyor, ayrıca paket uzunluğu felan hesaplarken bir hata yaparsanız canınız çok sıkılabiliyor, çünkü bu tarz hatalar kimi durumlarda uzun süre ortaya çıkmayabiliyor. (yazdığım network katmanındaki bir paketin boyutu ile ilgili hatayı 1.5 - 2 sene sonra şans eseri görmüştüm - arada sırada random client lar oyundan kopuyorlardı...:) )

2) Java,  .net gibi platformlardaki reflection mekanizmalarını kullanarak serialization işini otomatiğe bağlamak; kendi custom RPC mekanizmanı geliştirmek. ıyi yanı; el ile paket oluşturma zahmetinden kurtarıyor, kod teorik olarak daha az potansiyel bug lı oluyor; kötü yanı: her platforma uygun değil (managed olmayan bir ortamda ciddi meta programming gerektirir ki benim harcım değil açıkçası), paket başına bir miktar sabit overhead getirir (uygulamaya göre göz ardı edilebilir, ya da edilmeyebilir :) )

Yanlız java ile bir sunucu sistemi programlıyor iseniz her koşulda MINA gibi bir frameworke iletim katmanını bırakmanızı tavsiye ederim. Java tarafında blocklamalı + bol thread li socket kullanma devri biteli çok oluyor; ama raw NIO kullanmak da bir o kadar karın ağrısı.. böyle bir ortamda MINA gibi kütüphaneler ilaç gibi geliyor.

deniz.

Winsock yardım

« Yanıtla #38 : 17.02.2010 23:05:42 »
Hızlı düğmeleri aç

tesla

İleti: 426

Çevrimdışı
  • ****
  • Sr. Member
    • Profili Görüntüle
    • http://
@skate

Aslında bizim ki "fixed length messaging" gibi değil de diğer bahsettiğin "seperated"'a daya uygun gibi. Mesela mesajları için şöyle bir yapı kurduk:

Register Message     : R[user name]
Broadcast Message : B[sender];[Message]
Private Message      : P[sender];[receiver];[Message]
UserList Request      : L[sender]
Disconnect Message: D[sender]
Whois Message      : W[sender];[target]

Örnek: Pomer;skate;selam naber?

Gönderirken de:

Kod: [Seç]

private void sendMessage(String message)
{
    byte[] buf = message.getBytes();
    DatagramPacket packet = new DatagramPacket(buf, buf.length, m_serverAddress, m_serverPort);
    .
    .
}


şeklinde gönderdik. Her mesaj için "buf.length"'e göre gönderdiğimizden her seferinde 1024 yada 2048 byte göndermedik. Ama Server'dan alırken, kaç byte geleceğini bilmediğimizden gelen mesajları direk 1024'lük bir buffer'a yazdık. Ama Server'da gelen mesajlar için tanımlı buffer boyutunun (aşmadığımız sürece) bir sorun çıkarmayacağını düşünüyorum, yani sonuçta 10 byte geliyorsa, biz onu 1024'lük bir buffer'a yazıyorsak bunun trafiği etkilememesi lazım.

Yukardaki mesaj yapılarında da görüldüğü gibi mesaj kısımları ";" ile ayırdık. Aynen söylediğin gibi bir Clien'te mesajı paketle, sonra Server'da o mesajı yorumla ve gerekeni yap, sonra tekrar ";" ile birleştir git gide arap saçına dönüyor işler. Mesaj yapıları da değişirse, hem Client hem Server'da bir çok yerde kodları değiştirmek gerekiyor.

@deniz

Skate ile sayende artık kullanabileceğimiz bir sürü yöntem oldu :) . Benim okuduklarımdan karar verdiğim, ortak mesajları bir class'a toplamak. Farklı özellik gösteren mesajlar içinse her biri için ayrı class yapmak. Sonra bunları serialize-deserialize ile gönderip almak. Başlarına gelen overhead'i önemsememek. şuan için çok profosyonel işlerle uğraşmadığımızdan, özellikle vakit sıkıntısı olduğundan mesajlar bir şekilde gitsin ve kodlamada çok arap saçı olmasın kafi :)  ... Mina'yi sonraki projelerde kullanmayı deneyeceğiz.


Bu arada sırada RMI, Corba ile ilgili ödevler var. En son da Raknet ve C++ ile bir uygulama daha geliyor. Yeni sorulara hazırlıklı olun :)

Winsock yardım

« Yanıtla #39 : 18.02.2010 00:18:58 »
Hızlı düğmeleri aç

skate

İleti: 5.245

A Sinner Scener
Çevrimdışı
  • Administrator
  • *****
  • Hero Member
    • Profili Görüntüle
    • http://www.akaydin.com/
bir uyarıda buluniim hemen. UDP kullandığınız durumda peş peşe gönderilen iki paket tek paket gibi gelebilir. yani 1024'lük buffera siz paketleri tek tek almayı bekleseniz de uc uca eklenebilirler. bu nedenle eğer yapıyı şu anki haliyle kullanacaksanız start ve end için özel bir seperator kullanıp, bufferı her zaman multimessage gelebilecek gibi analiz etmeniz lazım. benim tavsiye edeceğim yöntem buffera yazılan herşeyi ikinci bir bufferın ucuna eklemeniz ve bu ikinci bufferda identify edilen paketin aradan silinmesi ancak geri kalan verinin korunması yönünde. iki parçalı gelen paketler ya da tek bir pakette birden fazla paket gelmesi durumlarını en kolay böyle aşarsınız.

Winsock yardım

« Yanıtla #40 : 18.02.2010 16:22:35 »
Hızlı düğmeleri aç

deniz

İleti: 22

Çevrimdışı
  • *
  • Newbie
    • Profili Görüntüle
    • http://www.cizbakalim.com
Corba kullanan kaldı mı ya :)