2012-04-16 22 views
8

जब हैंडलर में 2048bytes लेखन, messageRevieved विधि सभी डेटा प्राप्त करने के लिए दो बार बुलाया जाना चाहिए ... मैं कैसे में, हम केवल 1024bytes से कम डेटा लिख ​​और प्राप्त कर सकते हैं: हम कैसे लिख सकते हैं या प्राप्त कर सकते हैं?

कोड 2048bytes डेटा प्राप्त कर सकते

सर्वर:

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)); 
    } 
} 

सर्वर हैंडलर:

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(); 
    } 
} 

ग्राहक:

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)); 
    } 
} 

ग्राहक हैंडलर:

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

खेद है कि मैं सवाल समझ में नहीं आता। क्या आप अधिक विशिष्ट होने की कोशिश कर सकते हैं? –

+0

मुझे खेद है, मैं एक चीनी हूं और मेरी अंग्रेजी अच्छी नहीं है। नीचे मेरा प्रश्न है: क्योंकि मैं नेटटी का उपयोग कर रहा हूं, जब मैं 2048 बाइट्स (1024bytes से बड़ा) डेटा को एक हाथ से दूसरे में लिखता हूं, तो प्राप्त करने वाले हाथ को दो बार प्राप्त करना चाहिए, मैं एक बार में पूरे डेटा (1024bytes से बड़ा) को कैसे पुनर्जीवित कर सकता हूं ? – Gofier

उत्तर

5

वैसे आप हमेशा तय कर सकते हैं कि कितने बाइट्स एक समय में लिखने के लिए है, लेकिन आप निश्चित रूप से जब जानते हैं और कितने कभी नहीं बाइट प्राप्त होते हैं (यही कारण है कि एनआईओ समझ में आता है)। आपको इच्छित बाइट्स की एक निश्चित संख्या प्राप्त करने के लिए आपको अपने बफर को संभालने की आवश्यकता है। ऐसा करने के लिए आप फ़्रेमडेकोडर का उपयोग कर सकते हैं जो इस उद्देश्य के लिए डिज़ाइन है।

Additionaly, आप सुनिश्चित करें कि datas सत्य पर tcpNoDelay की स्थापना करके इस सॉकेट बफर में बहुत लंबा नहीं रहता कर सकते हैं, तो यह वर्तमान "फ्रेम" के लिए कोई प्रतीक्षा शारीरिक रूप से भेजने से पहले एक कुछ महत्वपूर्ण आकार तक पहुँचने के लिए होगा डेटा

अगर मैं अच्छी तरह से समझता हूं, तो आप लिख रहे हैं कि हम एक हाथ में 2048 बाइट्स कहें लेकिन दूसरी डेटा मैसेज में प्राप्त नहीं हुई है। इन सामान्य समस्याओं की जांच करने के लिए प्रयास करें:

  • आप आवेदन बहुत जल्दी समाप्त हो जाता है और datas अभी तक नहीं कर रहे हैं
  • अपने datas
  • "प्रेषक" के सॉकेट बफर में stucked रहे हैं क्योंकि आप पास नहीं था चैनल और tcpNoDelay विकल्प सत्य पर सेट नहीं किया गया था। यह सॉकेट को पैकेट भेजने से पहले कुछ अतिरिक्त बाइट्स के लिए इंतजार कर रहा है।
  • आप के रूप में हमें अपने कोड के कुछ हिस्से को दिखाने के लिए एक और स्थिति के लिए निर्धारित किया गया

कोशिश ChannelBuffer अंदर लेकिन एक कारण के लिए readerIndex सभी datas पढ़ा नहीं था, यह चीजों को आसान बनाना चाहिए। ..

जोड़ा 17/04/2012

तो मैं समझता हूँ कि आप एक बाइट सरणी रिसीवर को भेजने वाले से एक स्ट्रिंग के लिए कोडिंग पारित करने के लिए कोशिश कर रहे हैं। लिटल रिफैक्टर के बाद आपका कोड यहां दिया गया है:

---------------------------- कोड -------- -------------------- हाथ लिखें: प्रतिक्रिया।आकार()> 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 हाथ: दो बार प्राप्त होनी चाहिए, println() दो बार

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); 

पर अमल होगा इस तरह से है कि, आप के बजाय पैकेज org.jboss.netty.handler.codec.string में सीधे StringEncoder और StringDecoder का उपयोग करना चाहिए करने के लिए नहीं है। यह आपके लिए फ़्रेमिंग समस्या को संभालेगा। यदि आप अभी भी अपना कोड डीबग करना चाहते हैं, तो नेटिंग द्वारा प्रदान की गई लॉगिंगहैंडलर का उपयोग करें।

bootstrap.setOption("tcpNoDelay", true); 
दोनों पक्षों बूटस्ट्रैप में

: इसके अलावा, आप वास्तव में यह विकल्प सेट किया?

+0

सबसे पहले, मेरे प्रश्न का उत्तर देने के लिए धन्यवाद, मुझे खेद है कि मेरी अंग्रेजी बहुत अच्छी नहीं है। हाँ, जैसा कि आपने कहा था, जब मैं हैंडलर पर 2048 बाइट लिखता हूं, तो संदेश पुनर्प्राप्त विधि को सभी डेटा प्राप्त करने के लिए दो बार बुलाया जाना चाहिए ... मैं अभी अपना कोड दिखाऊंगा, आपको धन्यवाद। – Gofier

+0

वास्तव में आपको धन्यवाद! NumRenaud, जैसा कि आपने सुझाव दिया है, मैंने अपना कोड बदल दिया है, लेकिन समस्या अभी भी चालू है, मुझे यकीन है कि मैंने दोनों पक्षों में bootstrap.setOption ("tcpNoDelay", true) विकल्प सेट किया है, मैंने "child.tcpNoDelay" भी कोशिश की है, और मैं उपयोग करता हूं दोनों तरफ "SimpleChannelHandler"। – Gofier

+0

क्लाइंट में बूटस्ट्रैप.सेटऑप्शन ("tcpNoDelay", true) और बूटस्ट्रैप.सेटऑप्शन ("child.tcpNoDelay", सत्य) सर्वर में – RenaudBlue

2

सबसे पहले, ग्राहक के लिए, बूटस्ट्रैप विकल्प 'बच्चे' से प्रारंभ नहीं करना चाहिए:

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

इसके अलावा, आप क्लाइंट और सर्वर पर एक ही बंदरगाह का उपयोग नहीं करते !!

दूसरा, आपके पास कोई "करीबी" रणनीति नहीं है: आपका ग्राहक कब अपना काम जानना चाहता है? थ्रेड को नाकाबंदी खत्म करने से कैसे रोकते हैं? आप इस

सर्वर हैंडलर

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(); 
    } 
} 

ग्राहक बूटस्ट्रैप

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(); 
    } 
} 

अंत में क्या करना चाहिए, आप उदाहरण के एक बहुत पढ़ कर आप क्या कर रहे बेहतर ढंग से समझने की जरूरत है। वे मुख्य बंडल डाउनलोड में org.jboss.netty.example पैकेज के अंदर पाए जा सकते हैं।

+0

आपको बहुत बहुत धन्यवाद, मैं इसे निकाल दूंगा! धन्यवाद ! – Gofier

3

TruncatedChannelBuffer या BigEndianHeapChannelBuffer के साथ अपने ClientHandler में चैनलबफर के बजाय प्रयास करें। मुझे लगता है कि यह काम करेगा .. या अगर यह काम नहीं करता है, तो कृपया उत्पन्न अपवाद के stacktrace पोस्ट करें। मैंने अपने कोड में यह कोशिश की और यह काम किया .. मुझे आशा है कि यह आपकी मदद करेगा।

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 @ अच्छा अंक बनाता है। इसके अलावा, मैं Netty4 है, जो सभी ByteBufs गतिशील बनाता है का उपयोग करने जा सुझाव है, और जो chunked बनाता पढ़ता/प्रबंधन करने के लिए आसान लिखता है। "Porting the client" देखें।

उदाहरण के लिए,

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 भी चैनल विकल्प विन्यास के लिए टाइप-सुरक्षा, जो "child.tcpNoDelay" erro रोका होता है आर।

लेकिन नेटटी 4 के लिए बड़ी जीत अच्छी तरह से परिभाषित थ्रेड मॉडल है, जो नेट्टी अधिक उपयोग करने में आसान बनाता है।

0

आप इस प्रकार childHandler() में SocketChannel की स्थापना FixedRecvByteBufAllocator की जरूरत है:

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()); 
       ... 
      } 
     }); 
संबंधित मुद्दे

 संबंधित मुद्दे