UDP

2010-10-22 17 views
10

numaralı seri hale getirme nesnesini alma ve alma UDP kullanan bir sunucu işleminden seri hale getirilmiş bir nesneyi Java'daki bir istemci işlemine göndermeye çalışıyorum. Sorun, istemci alma yöntemi üzerinde engelleniyor olmasıdır. Birisi yardım edebilir mi? Burada UDP

nesneyi göndermek için sunucu kodu:

ClientModel C1= new ClientModel(100,"Noor","Noor",38,38,"asd"); 
    ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
    ObjectOutputStream oos = new ObjectOutputStream(baos); 
    oos.writeObject(C1); 
    oos.flush(); 
    byte[] Buf= baos.toByteArray(); 
    packet = new DatagramPacket(Buf, Buf.length, client, port); 
    socket.send(packet); 

ve burada nesneyi almak için istemci kod geçerli:

byte[] buffer = new byte[100000]; 
packet = new DatagramPacket(buffer, buffer.length); 
socket.receive(packet); 
System.out.println("packet received"); 

Sadece muktedir nesneyi almak istediğiniz yeniden yapılandırın ancak paketin kendisini alamıyorum.

+0

belki de arabelleği temizlemeniz gerekiyor ... – ultrajohn

cevap

13

Sana sonunda başarmak istediğiniz bilmiyorum ama UDP ile çalışan o kadar kolay değildir ... ana nedeni datagram paketleri Nesne Açıklaması geçerli:

Datagram paketleri için kullanılır bağlantısız bir paket teslimatı servisini uygulayın. Her bir mesaj, tek makineden, paketinde bulunan bilgilerle ilgili olarak yalnızca 'a dayalı olarak yönlendirilir. 'dan bir makineden diğerine gönderilen çoklu paketler, farklı şekilde yönlendirilebilir ve herhangi bir siparişine ulaşabilir. Paket teslimatı garantili değildir.

İyi öğretici udp çalışmasını engelleme hakkında http://download.oracle.com/javase/tutorial/networking/datagrams/clientServer.html

geçerli:

bu soketinden bir datagram paketi alır. Bu yöntem döndüğünde, DatagramPacket'in arabelleği, alınan verilerle doldurulur. Datagram paketi ayrıca gönderenin IP adresi, ve gönderenin makinesindeki port numarasını içerir.

Bu yöntem, bir datagram alınana kadar engellenir. datagram paket nesnesinin uzunluk alanı, alınan iletinin uzunluğunu içerir. iletisi, paketin uzunluğundan daha uzunsa, mesaj kesilir.

Gerçekten bunu test vermedi, ama ben eminim - açıklamaya dayalı - (100000 bayt alınana kadar senin durumunda) paket dolana kadar datagramsocket.reseive işlevi engelleyeceğini.

Gerçek faydalı yükün boyutunu ilettiğiniz, bilinen bir sabit uzunluğa sahip bir datagrampacket ile başlamanızı öneririm.Bir şey gibi: Diğer tarafta

public static void main(String[] args) { 
    ClientModel c1 = new ClientModel(); 
    c1.data = 123; 
    c1.name = "test"; 

    try { 
     ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
     ObjectOutputStream oos = new ObjectOutputStream(baos); 
     oos.writeObject(c1); 
     oos.flush(); 
     // get the byte array of the object 
     byte[] Buf= baos.toByteArray(); 

     int number = Buf.length;; 
     byte[] data = new byte[4]; 

     // int -> byte[] 
     for (int i = 0; i < 4; ++i) { 
      int shift = i << 3; // i * 8 
      data[3-i] = (byte)((number & (0xff << shift)) >>> shift); 
     } 

     DatagramSocket socket = new DatagramSocket(1233); 
     InetAddress client = InetAddress.getByName("localhost"); 
     DatagramPacket packet = new DatagramPacket(data, 4, client, 1234); 
     socket.send(packet); 

     // now send the payload 
     packet = new DatagramPacket(Buf, Buf.length, client, 1234); 
     socket.send(packet); 

     System.out.println("DONE SENDING"); 
    } catch(Exception e) { 
     e.printStackTrace(); 
    } 
} 

artık boyutlarını BİLMEK:

public static void main(String[] args) { 
    try { 
     DatagramSocket socket = new DatagramSocket(1234); 

     byte[] data = new byte[4]; 
     DatagramPacket packet = new DatagramPacket(data, data.length); 
     socket.receive(packet); 

     int len = 0; 
     // byte[] -> int 
     for (int i = 0; i < 4; ++i) { 
      len |= (data[3-i] & 0xff) << (i << 3); 
     } 

     // now we know the length of the payload 
     byte[] buffer = new byte[len]; 
     packet = new DatagramPacket(buffer, buffer.length); 
     socket.receive(packet); 

     ByteArrayInputStream baos = new ByteArrayInputStream(buffer); 
     ObjectInputStream oos = new ObjectInputStream(baos); 
     ClientModel c1 = (ClientModel)oos.readObject(); 
     c1.print(); 
    } catch(Exception e) { 
     e.printStackTrace(); 
    } 
} 

CientModel clas sı kullandı:

public class ClientModel implements Serializable{ 
    private static final long serialVersionUID = -4507489610617393544L; 

    String name = ""; 
    int data = 1; 

    void print() { 
     System.out.println(data +": " + name); 
    } 
} 

Bu kodu test edilmiş ve gayet güzel çalışıyor. Umarım bu yardımcı olur (By-Int-int ve çevresinde http://www.tutorials.de/java/228129-konvertierung-von-integer-byte-array.html var)

Düzenleme: Açıklamalarda belirtildiği gibi, genellikle UDP kullanmak çok kötü bir fikirdir, çünkü paketleriniz olup olmadığını bilmiyorsunuz Doğru sırayla veya hatta alınır. UDP bunu garanti etmez. Çok fazla programlama yapmadım, ama güvenebileceğin tek parça (eğer doğru anladıysam), eğer bir paket alırsan ve datagramın içine sığarsa (65.527 bytes - bkz. https://en.wikipedia.org/wiki/User_Datagram_Protocol) tüm şey. Yani mesajın geldiği ve nesnenin datagrama sığdığı sıraya dikkat etmezseniz, iyi olmalısınız.

Edit2: Kodla ilgili olarak: olduğu gibi kullanmayın. Bu sadece bir örnektir, UDP'ye göre sadece bir tip pakete sahip olmalısınız ve bu bilinen bir boyuta sahiptir. bu şekilde "boyut" u göndermeniz gerekmez. Yukarıda gösterildiği gibi kodu kullanırsanız ve bir paket düşerse, bir sonraki paket yanlış boyutta olacaktır (yani ilk paket bırakılır, aniden boyutu almak için yükün ilk baytını kontrol edersiniz).

+0

Ben de test edilmedim, ancak C recvfrom (2) 'nin açıklamasından, UDP bağlantısından okunmanın tüm datagram okunduğunda ve fiili sayı geldiğinde geri dönebileceği açıktır Okunan baytlar döndürülür (JDK olması durumunda DatagramPacket.length alanında olacaktır). Davranışı test etmek için basit Java echo istemcisini/sunucusunu yazmayı öneriyorum. –

+0

Datagramlar siparişten çıkabilir veya hiç bir zaman gelmeyebilir. Bir sonraki beklenen boyutu onaylamak için ilk paketi kabul etmeniz ve daha sonra yük taşıma paketini – user12345613

+0

ack etmeniz gerekebilir. Bu nedenle, gerçek yükü göndermeden önce uzunluğu gönderirsiniz? Bu durum durumu nasıl değiştiriyor? Kaynak yükü iletmek için her iki kaynak kodu alıntılarındaki sözdizimi aynı kalır. Tabii ki – iGbanam

1

ı did not gerçekten test, ama ben eminim - açıklamaya dayalı - (100000 bayt alınan oluncaya dek durumunda) paket dolana kadar datagramsocket.reseive fonksiyon engel olacağı konusunda.

Bu yanlıştır. Alma fonksiyonu, bir datagram alınana kadar bloke edilir, bu da tampon boyutundan daha küçük olabilir (ve genellikle olacaktır). Packet.getLength() yöntemi size ne kadar büyük olduğunu söyleyecektir.