tr-demoscene

the scene => coding => pc => Konuyu başlatan: paradox - 12.10.2009 14:58:15

Başlık: Winsock yardım
Gönderen: paradox - 12.10.2009 14:58:15
bir adet server ve bitanede client'im var...
serverdan client'e birkaç veri arka arkaya gönderdiğimde herşey normal oluyor..
Fakat client'den servera arka arkaya veri gönderdiğimde veriler karişiyor..

mesela:

client:
Gönder(x);
Gönder(y);
Px=GelenData();
Py=GelenData();

server:
Gönder(a);
Gönder(b);
Ax=GelenData();
Ay=GelenData();


burada float x,y,a,b değerlerini gönderiyorum..
serverdan gönderdiğim a,b sayıları client'de px,py oluyor..bunda bi problem yok..
Fakat client'den gönderdiğim x,y sayıları Ax,Ay sayıları karışıyor..
Ax=x (clientten gelen x) olucakken Ax=y oluyor arada sonra gene Ax=x oluyor..
Başlık: Winsock yardım
Gönderen: skate - 12.10.2009 15:25:50
biraz daha detay lazım. mesela TCP mi UDP mi kullanıyorsun? UDP'de paketlerin ulaşma sıralamalarında garanti yoktur. Yani sen önce A, sonra B göndersen de önce B sonra A ulaşabilir. TCP'de ise sıra korunur. UDP kullandığını varsayıyorum ve pakete birkaç bytelık bir header eklemeni ya da iki datayı tek bir pakette göndermeni öneriyorum.
Başlık: Winsock yardım
Gönderen: paradox - 12.10.2009 16:08:18
udp kullanıyorum.
Peki bu iki yada daha çok datayı tek pakette nasıl gönderebilirim.
Başlık: Winsock yardım
Gönderen: skate - 12.10.2009 16:41:38
paketi tamamen binary olarak düşüneceksin. sonuçta paketin içeriği bytelardan ibaret. her dilde yöntem değişir ancak float dediğin 4 byte birşey. peş peşe 2 float toplam 8 bytelık bir paket oluşturur. öteki tarafta byte byte okunan paketin ilk 4 byte'ı birinci değişkene, son 4 byte'ı ikinci değişkene alınabilir.
 
UYARI! UDP güvenilir bir protokol değildir, paket kaybı olabilir (hatta olur). Dolayısıyla TCP kullanmanı tavsiye ediyorum. UDP çok fazla adette gönderilen ve kayıp verinin aşırı problem olmayacağı veriler için idealdir. Örneğin audio, video streaming, MMO tarzı oyunlardaki bazı server/client iletişimi v.s. Yani eğer amacın aşırı yüklü bir işlem değilse UDP'yi tavsiye etmem, TCP garantilidir. Paket ulaşmazsa hata mesajı alabilir, gerekirse yeniden gönderebilirsin. UDP'de ise gönderdiğin paketi yanlış bir IP'ye bile göndersen, senden çıktıktan sonra bir kontrolün yoktur paket üzerinde. IP doğru bile olsa o anda bilgisayar/cihaz erişilmez durumdaysa bunu göremezsin. Tek yol kendi acknowledge mekanizmanı kurmandır ki basit birşey için gereksiz. TCP protokolü zaten sana bunu sağlıyor, checksum'ını ekliyor pakete, ulaştığını doğruluyor v.s.
Başlık: Winsock yardım
Gönderen: paradox - 12.10.2009 19:01:45
teşekkürler
Başlık: Winsock yardım
Gönderen: paradox - 20.01.2010 23:34:46
arkadaşlar ilk mesajımdaki olayı tcp ile hallettim..Lan olarak hızlı bi şekilde çalışıyor..Ama online denediğimde kasıyor..
ıkitane küp yaptım..bitanesi serverin biri clientin..birbirine hareket pozisyonlarını gönderiyorum kendim deniyorum serveri ve clienti açıp hiç bi sorun yok..online denediğmizde hem kendi kübüm hemde clientin kübü frame frame hareket ediyor..Neden böyle ola ki acaba:D
Başlık: Winsock yardım
Gönderen: skate - 21.01.2010 02:32:18
çünkü pozisyonu değil hareketi göndermen lazım. yani her koordinat değişiminde bir paket göndermek yerine tuşa basıldığında ve tuştan elini çektiğin anda yalnızca 2 paket göndererek gerisini client'a bırakman lazım. ancak bu defa da işin içine laglerden kaynaklanan sorunlar giriyor. ben şöyle yapıyorum, 2. pakette yani tuştan elini çektiğinde bir de coordinate correction bilgisi yolluyorum servera. Server tuştan el çekildiği anı biraz geç de alsa koordinatı düzeltebiliyor. Diğer clientlarda bu ufak bir geri atlama şeklinde görüntülenebiliyor. Bunu çözmek için de birkaç yol var.
 
1) ortalma lag miktarı bulunup tüm eventler lag miktarı kadar geriden takip edilebilir.
2) tuşlarla hareket yerine "point to click" yöntemi kullanılabilir. yani WASD gibi bir hareket yerine mouse ile clicklenen koordinata doğru hareket eder sprite.
 
Edit: WASD kullanmak istiyorsan işte bu durumda UDP daha makul bir çözüm olabilir. Genellikle nesneler sürekli hareket halinde olacakları için aradan 1-2 paket kaçması sorun olmaz. Dediğim gibi zaten koordinatlar hareket sona erdiği anda güncelleniyor. Bu da aklında bulunsun. Modern MMOlar TCP+UDP kullanıyor genelde. Inventory, alış veriş sistemi, görev sistemi v.s. kritik şeyler TCP ya da acknowledgelı UDP ile yapılırken sprite hareketleri plain UDP ile yapılıyor.
Başlık: Winsock yardım
Gönderen: Hydrogen - 21.01.2010 09:03:32
Iyi mmorpg'ler genelde karakter hareketleri icin dahi udp kullanmiyorlar. Zira, bir adamin herhangi bir yone gittigi bilgisi dahi, genelde tek paketle cozuluyor(skate'in dedigi bas-cek olayi), karakterler hizlanirken ivmelenme vs. cok fazla kullanilmiyor. Tek paketin dahi kaybi, isinlanma problemlerine bolca neden olur, ki UDP'de onemli yuzdelerde paketler kayboluyor. Zaten iyi dizayn edilmis oyunlarda buna cok da gerek de olmuyor. WoW mesela, oyunla ilgili her sey tcp. Udp'yi sadece voice chat icin kullaniyor. I can football gibi, hizin inanilmaz onemli oldugu bir oyunda dahi tcp yeterli.
 
Internet uzerinden kup cevirmeye neden ihtiyac duydugunu da anlayamadim. Bu sunucular genelde cok optimize yaziliyorlar. Milyonlarca bilgi gitmiyor paketlerde. Bir fizik olayi hala mmorpg'nin icine gomulebilecek durumda degil mesela. Sonucta udp de olsa, tcp de olsa aralarda birbirlerine kilometrelerce kablo ile baglanmis binlerce user var.
Başlık: Winsock yardım
Gönderen: paradox - 21.01.2010 18:48:56
hareket olayı için skate dediğini anladım..Ama belli bir durumu kontrol etmek için nası olucak.Yani oyuncuda 4 tane skil var diyelim..bunları kullanırken sürekli servera bilgi göndermesi lazım.Yada oyundaki yaratıkların Canları sürekli servera yollanıcak serverda kullanıcılara göndericek..

"Internet uzerinden kup cevirmeye neden ihtiyac duydugunu da anlayamadim"
Yani ben evde online oyun motoru yazamammı demek istedin.
Başlık: Winsock yardım
Gönderen: Hydrogen - 21.01.2010 20:20:00
Burasi demoscene forumu oldugundan, kup deyince aklima rotate eden kup geldi, boyle realtime net uzerinden donuyor, sen kupten dummy olarak bahsettin herhalde:)
 
Yani evde online oyun motoru yazamazsin demedim. Sadece kup cevirmeyle baglantisini kuramamistim.
Başlık: Winsock yardım
Gönderen: skate - 21.01.2010 20:44:37
Yanlış anlaşılma olmuş, paradox herhangi bir sprite için place holder olarak küp kullanmış. Yarın öbür gün bunlar player, enemy falan olacaklar yani :)
 
Paradox, benim de başlangıç seviyesi ancak çalışır durumda bir MMO engine'im var. Aslında yıllar önce başladım kodlamaya ama devam edemedim bir türlü. Çünkü altyapısı hoşuma gitmiyordu, transfer edilen paketleri hazırlamak, göndermek, öteki tarafta açmak için amele yöntemler kullanıyordum. şimdi çok daha güzel bir yapı hazırlayabilecek durumdayım ancak bu projeye sıra gelmesine çok var. Ben uğraşamıyorum, bare tanıdık bir indie developer uğaşsın böyle bir işle :) Sana benden tam destek. ılk preview'ı sabırsızlıkla bekleyeceğim.
Başlık: Winsock yardım
Gönderen: paradox - 21.01.2010 21:44:25
"Internet uzerinden kup cevirmeye neden ihtiyac duydugunu da anlayamadim. Bu sunucular genelde cok optimize yaziliyorlar. Milyonlarca bilgi gitmiyor paketlerde."

Ben şöyle anladım:Bu sunucular farklı..küple falan denemeyle olmaz..başında 2-3 tane koreli teknisyen gerekli gibi bişey canlandı kafamda:D..Neyse olay anlaşılmış sonuçta..

skate , bende uğraşıyorumda işte sorunumu yazdım..sürekli int,float şeklinde data yollamak yanlışmı..onu anlamadım..Teknoloji gelişti şimdi paket aç kapa uğraşamam..aklım ermedi benim ona:D
Başlık: Winsock yardım
Gönderen: skate - 22.01.2010 00:18:39
@paradox: En güzel yöntem şu sanırım (şimdi bunu dedim ya on tane daha güzeli gelir hehe). Client ve Server'ın paylaşacağı tüm veri tipleri için birer structure oluşturuyorsun. Örnek;
 
struct Player {
    float x;
    float y;
    char name[25];
};
 
tamamen attım kafadan. Sonra bu structure'ı olduğu gibi gönderiyorsun. Ama nasıl? Bunun için öncelikle datayı serialize etmen gerekiyor. Bunun birkaç yolu var. Aslında yukardaki örnekte 4+4+25 = 33 byte gibi hesaplayıp gönderebilirsin. Ama işin içine pointerlar bulaştımı bu yöntem patlar. Bu nedenle pointerları da referanslarına uygun bir biçimde serialize edebilecek daha gelişmiş bir serialization yöntemi lazım.
 
Bunlar şu anda bulduklarımdan bir kaçı.
 
http://s11n.net/c11n/
http://tpl.sourceforge.net/
http://www.enlightenment.org/p.php?p=about/efl/eet&l=en
 
Eminim daha onlarcası vardır. Bildiğim kadarıyla Nightlord'un kullandığı Boost da bu iş için ideal.
 
http://www.boost.org/doc/libs/1_41_0/libs/serialization/doc/index.html
Başlık: Winsock yardım
Gönderen: endo - 22.01.2010 00:30:31
hehehe walla ben de hydrogenle ayni seyi anlamisim, iki farkli pc'de birbiriyle senkronize donen 2 kup dusundum :P biri digerine "ben sola 72 derece donuyorum hadi sen de don" gibi paketler yolluyor felan :D
Başlık: Winsock yardım
Gönderen: deniz - 22.01.2010 10:53:14
udp mesajlaşma problemlerini (paket kaybı, yer değiştirme vb) acısızca halletmek için enet (http://enet.bespin.org/) gibi bir kütüphane kullanabilirsin. Daha da güzeli raknet gibi çok daha üst seviye bir network kütüphanesi kullanmak olacaktır. Zaten latency ile boğuşmak, client ları anlık lag altında senkronize edebilmek, veri frekansını azaltarak bandwidth den tasarruf etmek ve daha nice problem ile bolca uğraşmak zorunda kalacağın için birde alt seviye sıkıntılar ile debelenmek en son isteyeceğin şey olacaktır.

Eğer haberleşme mimarisinde yüksek oranda veri sıkıştırmaya ihtiyaç duymuyorsan kendi çapında bir rpc mekanizması oluşturmak akıllıca=acısız olacaktır. Bu sayede yeni paket tanımlama, paket yapısı değiştirme gibi bolca olan durumları çok rahat ve hızlı halledebilirsin. Üstelik yapıyı bir kez oturtursan bir daha da bug lar la felan uğraşmadan kodunu diğer kısımlarına konsantre olabilirsin.

Veri transferi garantiye alınmış UDP gibisi de yoktur, bence bundan şaşma. kolay gelsin. bol arge diliyorum.

Son mesajımdan beri öküz zaman geçmiş, kendime de koca bir oha diyorum, ve izleyici sandalyeme geri dönüyorum. - herkese sevgi, saygı.
Başlık: Winsock yardım
Gönderen: paradox - 22.01.2010 19:39:58
skate kaynaklar için teşekkür ederim..Anlattığın şekilde bi deniyeceğim..Birakaç bişey daha deniyeceğim ayrıca Birazda araştırma yapmam lazım..

deniz Yardımın için teşekkür ederim..O kütüphaneleri biliyorum.Onlarıda inceliyorum tabiki..Biraz araştırmam var ama Burda değişik fikirlerele kendim birşeyler karalarsam daha güzel olur..

Bizde şubat taliline giricez..Zamanım olucak uğraşmaya.Test etmek için buraya uygulamada koyucam.
Başlık: Winsock yardım
Gönderen: paradox - 28.01.2010 01:24:32
Arkadaşlar raknet'te yaptığım program kendimde deniyorum çalışıyor fakat online denediğimde bağlanmıyor..Bir sürüde komutu var çıkamadım işin içinden..
Port'umda açık zaten kendi kütüphanemde online bağlanıyordu.
raknet'de client portuda kullanılıyor ne ayaksa anlamadım zaten..
Paket gönderme olayı güzel ve hızlı ama online neden olmadı anlamadım..
ıngilizcem pek iyi değil ..şimdi foruma sorucam ama iş uzuycak anlaşamıcaz falan..
Bilgisi olan varsa bu konuda yardım bekliyorum
Başlık: Winsock yardım
Gönderen: skate - 28.01.2010 01:49:44
1) Server olarak kullandığın makinenin firewall'unda UDP portunun açık olduğundan emin ol. Yanlışlıkla TCP açmış olabilirsin diye belirttim.
2) ADSL arkasındaysan modem ayarlarından kendi iç IP'ne yönlendirme yapman lazım (NAT ayarı). Daha sonra dışardan bağlanacak olan kişi senin whatismyip.com'dan görebileceğin dış IP'ne bağlanmalı.
 
Bunları zaten biliyor/yapmış olabilirsin. Ben elimdeki az veriyle ihtimalleri saydım sadece.
Başlık: Winsock yardım
Gönderen: deniz - 28.01.2010 16:11:45
loopback üzerinden düzgün çalıştığına göre büyük ihtimal ile skate inde dikkat çektiği üzere bir şekilde adsl router a takılıyor paketlerin.

Raknet bağlantı yönetimi sunucu ve istemci için ortak olarak PeerInterface üzerinden yürütüyor. Biraz alışılmadık bir durum ama özellikle peer-to-peer uygulama yazıyorsan çok işlevsel bir hale geliyor (adı üstünde) . Fakat günümüzde genelde client-server işler yapıldığından bu nesne ilk bakışta biraz garip gözüküyor gerçekten. Client interface de port tanımlamak zorunda değilsin, bu tanımlamanın zorunluğu sadece server için geçerli.
Başlık: Winsock yardım
Gönderen: paradox - 29.01.2010 14:47:32
1) udp portu açık değilmiş..onu açınca düzeldi:rolleyes:
şimdi sorununum şu..servera 2 tane client bağlıyorum bunlar birbirine sayı değerleri gönderiyor.
Fakat 3. clienti sokduğumda bundan gelen değeri diğer client'ler alırken karışıyor..
Deniz sanırım raknet tecrüben var..kodu buraya atıyorum

unsigned char msgID = p->data[0];
if(msgID==ID_NEW_INCOMING_CONNECTION)
{connect++;}

Burda server  int tanımlı A yı alıyor clientlere gönderiyor.

RakNet::BitStream ss;
ss.Write(unsigned char(ID_WRITE));
ss.Write(A);
server->Send(&ss, HIGH_PRIORITY, RELIABLE_ORDERED, 0,p->systemAddress, true);

 
 RakNet::BitStream bs(p->data,p->length,false);
unsigned char packetID;    
    bs.Read(packetID);
  switch(packetID) {
        case ID_MYOBJECT_CREATED:
        bs.Read(A);
        server->DeallocatePacket(p);
    p = server->Receive();
break;
        default:
printf("%d\n",A);

benim istediğim diğer oyunculardan gelen verileri arıyıp array'da tutmak..Başka yoluda vardır tabi..Bu kütüphaneyi bilmediğimden bunu kurcaladım ilk.
Başlık: Winsock yardım
Gönderen: skate - 29.01.2010 15:04:12
senin kodların üzerinden yorum yapamayacağım ancak ben bu işi şöyle çözmüştüm.
 
Kod: [Seç]
void sendToAll(CHAR* data, DWORD length) {
    WSABUF buffer;
    buffer.buf = data;
    buffer.len = length;
    ClientConnection* cc = cc->first;
    while(cc != NULL) {
        try {
            WSASend(cc->getSocket(), &buffer, 1, NULL, 0, NULL, NULL);
        } catch(CHAR* error) {
            printf("Error occured: %s\n",error);
        }
        cc = cc->next;
    }
}
 
void sendToRest(ClientConnection* sender, CHAR* data, DWORD length) {
    WSABUF buffer;
    buffer.buf = data;
    buffer.len = length;
    ClientConnection* cc = cc->first;
    while(cc != NULL) {
        if(cc != sender) {
            try {
                WSASend(cc->getSocket(), &buffer, 1, NULL, 0, NULL, NULL);
            } catch(CHAR* error) {
                printf("Error occured: %s\n",error);
            }
        }
        cc = cc->next;
    }
}
 
void reply(ClientConnection* sender, CHAR* data, DWORD length) {
    WSABUF buffer;
    buffer.buf = data;
    buffer.len = length;
    try {
        WSASend(sender->getSocket(), &buffer, 1, NULL, 0, NULL, NULL);
    } catch(CHAR* error) {
        printf("Error occured: %s\n",error);
    }
}

sendToAll - sender bilgisine ihtiyaç duymuyor. Linked listte ne kadar client varsa hepsine gönderiyor aynı bilgiyi.
 
sendToRest - hemen hemen SendToAll ile aynı ancak fazladan sender parametresi alıyor. paketi gönderen her kimse o hariç tüm clientlara gönderiyor paketleri.
 
reply - bu ise sadece paketi gönderene yanıt olarak paket gönderiyor.
 
Benim başka bir case'e ihtiyacım olmamıştı. Yani gruplar halinde bir client grubuna paket göndermem gerektirecek bir durum olmamıştı. O tür ihtiyaçlar doğdukça bu fonksiyonların birkaç ilave parametre alan versiyonlarına da ihtiyaç olacaktır tabii ki.
Başlık: Winsock yardım
Gönderen: deniz - 29.01.2010 15:50:21
Ben genellikle bilmediğim bir kütüphane ile uğraşırken ilk olarak kütüphane ile gelen -varsa- örneklerden işime yarayabilecekler üzerinden gidiyorum. Yapacağım ufak tefek değişiklikler ile bu kod üzerinde birşeyleri bozana kadar denemelerimi yapıyorum, sistemi iyice anladığımı düşündüğüm noktada kendi kodumu öğrendiklerim doğrultusunda baştan temize çekip yazıyorum. Sana bu yöntemi kullanmanı tavsiye ederim; raknet dökümantasyonu harika değil, ama raknet ile beraber gelen örnek uygulamalar oldukça yeterli. Ayrıca internet te insanların hazırladığı pekçok giriş seviyesi döküman da var; şu aşağıdaki döküman ilk başladığımızda bizim bayağı işimize yaramıştı; izlemeni tavsiye ederim; Açıkçası buradaki problemini tam olarak anlayamadım, kusura bakma.

step1 deki irrlicht e özgü kısımları atlatırsan gerisi network kodu;
http://www.daveandrews.org/articles/irrlicht_raknet/step1.htm

Kolay gelsin, iyi çalışmalar;

ekleme;
Üstteki mesajında ingilizcenin yeterli olmadığından dem vurmuşsun; ukalalık olarak algılama fakat bence bu noktada kendin için yapacağın en iyi şey raknet felan bırakıp teknik belge okuyabilecek kadar ingilizce bilgini ilerletmen. "Salak mı ne bu herif" diyebilirsin, ama inan ki yabancı belgeleri anlayamıyor isen programlama ile uğraştığın her alanda bir şekilde biryerlerde çarçabuk takılıp kalmaya ve yılgınlıkla başladığın işi bırakmaya mecbur kalacaksın. Umarım yanlış anlaşılmam.
Başlık: Winsock yardım
Gönderen: skate - 29.01.2010 16:21:18
ıngilizce konusunda yeni bir tartışma topici açılabilir dilerseniz. Ben konuyu çok dağıtmadan sadece ıngilizce harici bilmediğim dillerden yayınlanmış (buna uzak doğu gibi harflerini bile okuyamadığım diller de dahil olmak üzere) dökümanlardan bile faydalanabildiğimi hatırlatmak isterim. Yani bu konuda çabuk teslim olmamak gerekiyor. Elbette ki ıngilizce bilmeyen kişi dökümanı zevkle overview'dan itibaren adım adım okuyup, dökümanı yazanın espiri anlayışına kadar zevkini çıkararak okumaktan mahrum kalıyor. Ancak bunun gibi bir örnekte dökümanda verilecek kod örnekleri bile genellikle konuyu anlamaya yetecektir.
Başlık: Winsock yardım
Gönderen: paradox - 29.01.2010 17:22:16
Benim kodda bi hata yok..skate'in sendToRest olayı gibi server bir clientten alıp diğerine veri yoluuyor..Gönderdiğin link'de temel aynı ben bi fark göremedim..

(gönderdiğin örnek koddan aldım)

switch
(packetID) {
   case PACKET_ID_LINE:
        int x1, y1, x2, y2;
       
        dataStream.Read(x1);
        dataStream.Read(y1);
        dataStream.Read(x2);
        dataStream.Read(y2);
       
        SendLineToClients(server, p->playerId, x1, y1, x2, y2);
    break;
Burda Read(x1) i okuyup gönderme işlemini gönderen kullanıcı hariç diğerlerine gönderiyor..

 Benim takıldığım yer şu..4 veya 5 tane bağlantıdan bilgi geliyor servera ..bu bilgiler bi cliente gidiyor..
Clientin aldığı bilgilerin kimden geldiğini , kime işleneceğini nasıl anlarım..

server gönderdi
datastream.Write(x1)

client aldı
datastream.Read(x1)

Bu x1 in içinde diğer oyuncuların bilgileride var ..Bunları nasıl ayırd edicem..
mesela :

KendiPozisyonum(x1,y1);
gönder(x1,y1);

Oku(gelenx1,geleny1)
Oyuncu[1].poz(gelenx1,geleny1)
Oyuncu[2].poz(gelenx1,geleny1);
..
Oyuncu[n].poz(gelenx1,geleny1);

(dediğim zaman hata olur sanırım) bunun için nası bi yöntem var onu sordum..
Başlık: Winsock yardım
Gönderen: deniz - 29.01.2010 18:30:30
Bunu kendi oluşturduğun protokol içerisinde halletmen gerekir. Örneğin bir oyuncunun pozisyonunu güncellemen gerekiyor diyelim. Sunucu p1 oyuncusunun güncel pozisyon bilgisine sahip (p1x,p1y gibi olsun). Bu bilgiyi p1 hariç diğer tüm oyunculara göndereceğini varsayalım ( aslında p1 e de tekrar göndermek bir tercih olabilir ama konumuz ile bir alakası yok şimdi bunun). Veriyi gönderirken sadece p1x,p1y verisini değil, bu verinin kime ait olduğunu da pakete iliştirmen gerekir. Her oyuncuya bir numerik id verip (0,1,2 gibi ) bu sayıları oyuncuları ayırmak için kullanabilirsin.

Sunucu veri okurken kimden geldiğini biliyor, socket bağlantı noktaları farklı. Ama client tarafında tüm haberleşme sadece sunucu ile yapıldığı için protokol içerisinde bu ayrımı halletmek bir mecburiyet.

deniz.
Başlık: Winsock yardım
Gönderen: skate - 29.01.2010 23:02:33
benim sistem şöyle işliyor. ilk bağlantıda client server'dan bir ID request ediyor. server bu ID'yi üretip client'a geri yolluyor. client kendi bilgilerini server'a yolluyor. server client'a diğer tüm playerların o an için mutlaka ihtiyaç duyulan bilgileri varsa onları gönderiyor (kısaca bilgilerin bir kısmı başlangıçta cacheleniyor).
Başlık: Winsock yardım
Gönderen: paradox - 31.01.2010 18:26:44
Alıntı yapılan: skate;22436
benim sistem şöyle işliyor. ilk bağlantıda client server'dan bir ID request ediyor. server bu ID'yi üretip client'a geri yolluyor. client kendi bilgilerini server'a yolluyor. server client'a diğer tüm playerların o an için mutlaka ihtiyaç duyulan bilgileri varsa onları gönderiyor (kısaca bilgilerin bir kısmı başlangıçta cacheleniyor).

Bende onu yapmaya çalıştım aslında ama ID'yi nasıl üreticem ne şeklinde göndericem orda karıştırdım olayı..
Başlık: Winsock yardım
Gönderen: skate - 31.01.2010 19:45:45
ID iki şekilde olabilir.
 
1) Autoincrement. Her yeni requestte bir artar gönderilen ID. Aradan bir client disconnect olsa bile onun ID'si başka bir client'a verilmez (daha doğrusu bununla uğraşılmaz).
2) Unique bir ID generate edilebilir. GUID benzeri birşey ancak o kadar uzun olmak zorunda değil. Örneğin Base64 encoding ile üretilmiş 8 haneli bir string ya da doğrudan 8 bytelık random bir ID iş görecektir. Bana kalırsa bir float genişliği bile (4 byte) bu iş için yeterli olacaktır.
 
1. yöntem çok daha mantıklı bence. Sonuçta 32 bit olarak düşünecek olursak 4 milyardan fazla client bağlanana kadar zaten server en az bir kez restart edilecektir öyle değil mi?
Başlık: Winsock yardım
Gönderen: spritus - 31.01.2010 23:26:38
player id'leri bir database'den de okunabilir. login olup oturum açan her player, register olurken aldığı id'yi oturum boyunca kullanabilir :D
Başlık: Winsock yardım
Gönderen: skate - 01.02.2010 07:10:53
bu doğru, ancak şöyle bir durum var. server'a bir connection request geldiği anda o connection'a özel bir obje yaratılıyor ve bu connection ile linkleniyor. sonrasında artık o clienta özel hiçbirşey üretilmese de onunla unique bir haberleşme sağlanabiliyor. kısacası hiçbir ID olmasa da o clientdan gelen paket diğer clientlarla karışmadan izole bir biçimde değerlendirilebiliyor server tarafında. ID'ye ihtiyaç duyulmasının nedeni tamamen diğer clientlarla ilgili. bir player hareket ettiği zaman diğer clientlara bunu bildirirken onun hangi player olduğunu bir biçimde ifade etmek gerekiyor. ancak authentication mecbur tutulmadan da o anda üretilmiş bir ID yeterli oluyor.
Başlık: Winsock yardım
Gönderen: tesla - 16.02.2010 01:36:34
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 (http://inspire13.com/other/pipboy/PipBoy_chat.rar) '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?
Başlık: Winsock yardım
Gönderen: skate - 16.02.2010 10:53:12
@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.
Başlık: Winsock yardım
Gönderen: tesla - 16.02.2010 15:04:39
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 ;)
Başlık: Winsock yardım
Gönderen: deniz - 16.02.2010 18:51:16
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/
Başlık: Winsock yardım
Gönderen: skate - 16.02.2010 19:37:21
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.
Başlık: Winsock yardım
Gönderen: tesla - 17.02.2010 02:07:50
@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 :)
Başlık: Winsock yardım
Gönderen: skate - 17.02.2010 03:05:53
@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.
Başlık: Winsock yardım
Gönderen: deniz - 17.02.2010 09:45:20
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.
Başlık: Winsock yardım
Gönderen: tesla - 17.02.2010 23:05:42
@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 :)
Başlık: Winsock yardım
Gönderen: skate - 18.02.2010 00:18:58
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.
Başlık: Winsock yardım
Gönderen: deniz - 18.02.2010 16:22:35
Corba kullanan kaldı mı ya :)