2012-04-16 9 views
8

, messageRevieved yöntemi ben, sadece yazmak ve 1024bytes daha az veri alabilir: yazabiliriz veya daha fazla alabilir nasıl? işleyicisi içinde 2048bytes yazarken

Kanununda 2048bytes veri alabilir nasıl ... tüm verileri almak için iki kez çağrılmalıdır

Sunucu:

public class Server{ 
    public static void main(String[] args){ 
     ChannelFactory factory=new NioServerSocketChannelFactory(
      Executors.newCachedThreadPool(), 
      Executors.newCachedThreadPool()); 
     ServerBootstrap bootstrap=new ServerBootstrap(factory); 
     bootstrap.setPipelineFactory(new CarPipelineFactory()); 

     bootstrap.setOption("child.tcpNoDelay", true); 
     bootstrap.setOption("child.keepAlive", true); 

     bootstrap.bind(new InetSocketAddress(8989)); 
    } 
} 

Sunucu İşleyici:

public class ServerHandler extends SimpleChannelHandler{ 

    public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e){ 
     byte[] resp=data.getBytes();//data is a String greater than 1024bytes; 
     ChannelBuffer buffer=ChannelBuffers.buffer(resp.length); 
     buffer.writerBytes(resp); 
     e.getChannel().write(buffer); 
     buffer.clear(); 
    } 
} 

Müşteri:

public class Client{ 
    public static void main(String[] args){ 
     ChannelFactory channelFactory=new NioClientSocketChannelFactory(
      Executors.newCachedThreadPool(), 
      Executors.newCachedThreadPool()); 
     ClientBootstrap bootstrap=new ClientBootstrap(channelFactory); 
     bootstrap.getPipeline().addLast("handler", new PhoneClientHandler()); 

     bootstrap.setOption("child.tcpNoDelay", true); 
     bootstrap.setOption("child.keepAlive", true); 

     bootstrap.connect(new InetSocketAddress("127.0.0.1",8181)); 
    } 
} 

Müşteri Handler:

public class ClientHandler extends SimpleChannelHandler{ 
    public void messageRecieved(ChannelHandlerContext ctx, ChannelStateEvent e){ 
     ChannelBuffer buffer=(ChannelBuffer)e.getMessage(); 
     int size=buffer.readableBytes(); 
     byte[] bytes=new byte[size]; 
     buffer.readBytes(bytes); 
     buffer.clear(); 
     System.out.println(new String(bytes));//if the data size>1024,the String will speprate into parts. 
    } 
} 
+0

Üzgünüm soruyu anlamıyorum. Daha spesifik olmaya çalışabilir misin? –

+0

Üzgünüm, bir Çinliyim ve İngilizcem iyi değil. aşağıda benim soru: 2020bytes (herhangi bir 1024bytes daha büyük) veri bir elden diğerine yazdığım zaman, netty kullanarak, alıcı el iki kez, tüm verileri (1024bytes daha büyük) bir kez revieve nasıl ele almak gerekir ? – Gofier

cevap

5

Eh her zaman bir defada yazmak için kaç bayt karar verebilir, ama kesinlikle zaman bilmek ve kaç asla baytlar alınır (bu yüzden NIO mantıklıdır). İstediğiniz sabit sayıda bayt almak için kendi arabelleğinizi tutmanız gerekir. Bunu yapmak için bu amaçla tasarımdır bir FrameDecoder kullanabilirsiniz.

Ek olarak, sen veriler true TcpNoDelay ayarlayarak gönderen soket tamponu içinde çok uzun kalmaz emin olun, bu nedenle geçerli "çerçeve" hayır bekle fiziksel göndermeden önce belirli kritik büyüklüğe ulaşmak olacak veriler.

Ben de anlamak

, sen en 2048 bir elinde Byte ancak tüm veriler diğer taraftan messagedReceived olayı alınamayan diyelim yazıyorsun? bu sık karşılaşılan sorunları kontrol etmek deneyin:

  • size uygulama çok erken sona erer ve veriler henüz yakınvermedi çünkü
  • senin veriler
  • "gönderici" nin soket tamponu içinde stucked edilir geldi edilmez Kanal ve TcpNoDelay seçenek true ayarlanmamış. Bu, soketin paketi göndermeden önce bazı ek baytları beklemesine neden oluyor. Bize kod kısmını göstermek için başka bir pozisyona

deneyin ayarlanmış olarak

  • bunu işleri kolaylaştırmak gerektiğini readerIndex ChannelBuffer içeride ama bir nedeni tüm verilerin okumadım. ..

    EKLENDİ

    sana göndericiden alıcıya bir dize için kodlama yapan bir bayt dizisi aktarmaya çalıştığınız anlıyorsanız 17/04/2012.

    ---------------------------- kod --------: Burada bir seçilmesinin Refactor sonra kodudur -------------------- el yazınız: cevap.boyut()> 1024bytes

    byte[] datas = ((String)msg).getBytes("UTF-8"); //ALWAYS SPECIFY THE ENCODING 
    ChannelBuffer buffer = ChannelBuffers.wrap(datas); //USE DIRECTLY THE ARRAY 
    System.out.println(buffer); //buffer'size>1024 here 
    channel.write(buffer); 
    

    ---------------------------- recieve elle: İki kez alma gerektiğini println() iki kez

    ChannelBuffer buffer = (ChannelBuffer) event.getMessage(); 
    System.out.println(buffer) //buffer'size once 1024,once the remainder size 
    byte[] datas =buffer.readBytes(buffer.readableBytes()).array() 
    String msg=new String(datas , "UTF-8"); //BAD IDEA because the bytes sequence of the last UTF-8 char could be uncompleted there 
    System.out.println(str); 
    

    yürütülür Bu yerine org.jboss.netty.handler.codec.string pakette doğrudan StringEncoder ve StringDecoder kullanmalıdır, bunu yapmanın yolu değildir. Çerçeveleme problemini sizin için halledecektir. Kodunuzu hata ayıklamak istiyorsanız, Netty tarafından sağlanan LoggingHandler kullanın. Her iki taraf da göbeğini de

    bootstrap.setOption("tcpNoDelay", true); 
    

    : Ayrıca gerçekten bu seçeneği ayarlamak mı? Her şeyden

  • +0

    her şeyden önce, sorumu yanıtladığınız için teşekkür ederim, çok özür dilerim ingilizcem çok iyi değilsiniz, dediğin gibi, işleyicide 2048bayt yazdığımda, messageRevieved yöntemi tüm verileri almak için iki kez çağrılmalıdır ... Kodumu şimdi göstereceğim, teşekkürler Agian. – Gofier

    +0

    gerçekten teşekkür ederim! NumRenaud, önerdiğin gibi kodumu değiştirdim ama sorun hala açık, ben her iki tarafta bootstrap.setOption ("tcpNoDelay", true) seçeneğini ayarladığımdan eminim, ayrıca "child.tcpNoDelay" denedim ve kullanıyorum Her iki tarafta "SimpleChannelHandler". – Gofier

    +0

    bootstrap.setOption ("tcpNoDelay", true) istemcideki ve bootstrap.setOption ("child.tcpNoDelay", true) sunucuda – RenaudBlue

    2

    Birincisi, müşteri için, önyükleme seçeneği 'çocuk' ile başlar olmamalıdır:

    bootstrap.setOption("tcpNoDelay", true); 
    bootstrap.setOption("keepAlive", true); 
    

    Ayrıca istemci ve sunucu üzerinde aynı bağlantı noktasını kullanmayın !!

    İkincisi, "yakın" bir stratejiniz yok: Müşteriniz ne zaman işinin bittiğini varsayalım? İpliğin erken sona ermesini nasıl önlersiniz? Sen Nihayet bu

    SUNUCU Handler

    public class ServerHandler extends SimpleChannelHandler{ 
    
        public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e){ 
         byte[] resp=data.getBytes();//data is a String greater than 1024bytes; 
         ChannelBuffer buffer=ChannelBuffers.buffer(resp.length); 
         buffer.writerBytes(resp); 
         e.getChannel().write(buffer); 
         buffer.clear(); 
         e.getChannel.close(); 
        } 
    } 
    

    MÜŞTERİ Bootstrap

    public class Client{ 
        public static void main(String[] args){ 
         ChannelFactory channelFactory=new NioClientSocketChannelFactory(
          Executors.newCachedThreadPool(), 
          Executors.newCachedThreadPool()); 
         ClientBootstrap bootstrap=new ClientBootstrap(channelFactory); 
         bootstrap.getPipeline().addLast("handler", new PhoneClientHandler()); 
    
         bootstrap.setOption("child.tcpNoDelay", true); 
         bootstrap.setOption("child.keepAlive", true); 
    
         // Start the connection attempt. 
         ChannelFuture future = bootstrap.connect(new InetSocketAddress("127.0.0.1",8181)); 
    
         // Wait until the connection is closed or the connection attempt fails. 
         future.getChannel().getCloseFuture().awaitUninterruptibly(); 
    
         // Shut down thread pools to exit. 
         bootstrap.releaseExternalResources(); 
        } 
    } 
    

    yapmalıyım sen örnekler çok okuyarak ne yaptığınızı daha iyi anlamamız gerekir. Ana paketlenmiş indirmede org.jboss.netty.example paketinin içinde bulunabilirler.

    +0

    Çok teşekkür ederim, onu bulacağım! teşekkür ederim ! – Gofier

    3

    ClientHandler numaranızda kanal bloğu yerine veya BigEndianHeapChannelBuffer ile deneyin. Bence işe yarayacak .. ya da işe yaramıyorsa, yaratılan istisnanın stacktrace'ını nazikçe gönderin. Bunu kodumda denedim ve işe yaradı ... Umarım bu size yardımcı olur.

    public void messageReceived(ChannelHandlerContext channelHandlerContext,MessageEvent messageEvent) throws Exception { 
    
        Object messageObject = messageEvent.getMessage(); 
    
        // if size of message < 1024 then TruncatedChannelBuffer is returned. 
    
        if (messageObject instanceof TruncatedChannelBuffer) { 
    
         try { 
    
          TruncatedChannelBuffer truncatedChannelBuffer = (TruncatedChannelBuffer) messageObject; 
    
          byte[] byteArray = new byte[truncatedChannelBuffer.readableBytes()]; 
    
          truncatedChannelBuffer.readBytes(byteArray); 
    
          System.out.print(" Message = "+new String(byteArray)); 
    
          truncatedChannelBuffer.clear(); 
    
         } catch (Exception e) { 
    
          System.out.println("Exception in MessageReceived..."); 
    
          e.printStackTrace(); 
    
    
         } 
        } 
        // if size of message > 1024 then BigEndianHeapChannelBuffer is returned. 
    
        if (messageObject instanceof BigEndianHeapChannelBuffer) { 
    
         try { 
    
          BigEndianHeapChannelBuffer bigEndianHeapChannelBuffer = (BigEndianHeapChannelBuffer) messageObject; 
    
          byte[] byteArray = new byte[bigEndianHeapChannelBuffer.readableBytes()]; 
    
          bigEndianHeapChannelBuffer.readBytes(byteArray); 
    
          System.out.print(" Message = "+new String(byteArray)); 
    
          bigEndianHeapChannelBuffer.clear(); 
    
    
         } catch (Exception e) { 
    
          System.out.println("Exception in MessageReceived..."); 
    
          e.printStackTrace(); 
    
         } 
        } 
    
    }  
    
    1

    RenaudBlue @ iyi puan yapar. "Nio" den "OIO" ve "MİT" den "Oio" değiştirmek ve hangi yığın halinde yapar/yönetmek daha kolay yazar okur. "Porting the client" Bkz. Örneğin

    ,

    private void sendNumbers() { 
        // Do not send more than 4096 numbers. 
        boolean finished = false; 
        MessageBuf<Object> out = ctx.nextOutboundMessageBuffer(); 
        while (out.size() < 4096) { 
         if (i <= count) { 
          out.add(Integer.valueOf(i)); 
          i ++; 
         } else { 
          finished = true; 
          break; 
         } 
        } 
    
        ChannelFuture f = ctx.flush(); 
        if (!finished) { 
         f.addListener(numberSender); 
        } 
    } 
    
    private final ChannelFutureListener numberSender = new ChannelFutureListener() { 
        @Override 
        public void operationComplete(ChannelFuture future) throws Exception { 
         if (future.isSuccess()) { 
          sendNumbers(); 
         } 
        } 
    }; 
    

    Netty4 da "child.tcpNoDelay" Erro engel olurdu kanal seçeneği yapılandırma için tip-güvenlik vardır r.

    Ancak Netty4 için büyük bir kazanç, Netty çok kullanımını daha kolay hale getiren iyi tanımlanmış bir iplik modelidir.

    0

    Sen aşağıdaki gibi childHandler() içinde SocketChannel kurulumu FixedRecvByteBufAllocator gerekir:

    bootstrap.childHandler(new ChannelInitializer<SocketChannel>() { 
          @Override 
          protected void initChannel(SocketChannel ch) throws Exception { 
           ch.config().setRecvByteBufAllocator(new FixedRecvByteBufAllocator(2 * 1024)); 
           ChannelPipeline pipeline = ch.pipeline(); 
           pipeline.addLast("idleStateHandler", new IdleStateHandler(0, 0, 5)); 
           pipeline.addLast(new StringEncoder()); 
           pipeline.addLast(new StringDecoder()); 
           ... 
          } 
         }); 
    
    İlgili konular