浏览代码

The KernelAdapter now keeps a rolling message buffer
for the endpoints when using a reliable connection.
There is no guarantee that the buffers going out from
a client won't be chopped up by the networking stack
in various ways. It was always the intent to accumulate
them like this (the client side already does after all)
but it was an oversight. It's a testament to modern
networking that this hasn't come up in practice yet.


git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7449 75d07b2b-3a1a-0410-a2c5-0572b91ccdca

PSp..om 14 年之前
父节点
当前提交
17221395dc
共有 1 个文件被更改,包括 46 次插入3 次删除
  1. 46 3
      engine/src/networking/com/jme3/network/base/KernelAdapter.java

+ 46 - 3
engine/src/networking/com/jme3/network/base/KernelAdapter.java

@@ -34,7 +34,9 @@ package com.jme3.network.base;
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
+import java.util.Map;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -69,6 +71,10 @@ public class KernelAdapter extends Thread
     private Kernel kernel;
     private MessageListener<HostedConnection> messageDispatcher;
     private AtomicBoolean go = new AtomicBoolean(true);
+ 
+    // Keeps track of the in-progress messages that are received
+    // on reliable connections
+    private Map<Endpoint, MessageProtocol> messageBuffers = new ConcurrentHashMap<Endpoint,MessageProtocol>();
     
     // Marks the messages as reliable or not if they came
     // through this connector.
@@ -107,6 +113,10 @@ public class KernelAdapter extends Thread
  
     protected void connectionClosed( Endpoint p )
     {
+        // Remove any message buffer we've been accumulating 
+        // on behalf of this endpoing
+        messageBuffers.remove(p);
+    
         server.connectionClosed(p);
     }
  
@@ -156,16 +166,49 @@ public class KernelAdapter extends Thread
         }
     }
 
+    protected MessageProtocol getMessageBuffer( Endpoint p )
+    {
+        if( !reliable ) {
+            // Since UDP comes in packets and they aren't split
+            // up, there is no reason to buffer.  In fact, there would
+            // be a down side because there is no way for us to reliably
+            // clean these up later since we'd create another one for 
+            // any random UDP packet that comes to the port.
+            return new MessageProtocol();
+        } else {
+            // See if we already have one
+            MessageProtocol result = messageBuffers.get(p);
+            if( result != null ) {
+                result = new MessageProtocol();
+                messageBuffers.put(p, result);
+            }
+            return result;
+        }
+    }
+
     protected void createAndDispatch( Envelope env )
     {
-        MessageProtocol protocol = new MessageProtocol();
+        MessageProtocol protocol = getMessageBuffer(env.getSource()); 
     
         byte[] data = env.getData();
         ByteBuffer buffer = ByteBuffer.wrap(data);
 
         int count = protocol.addBuffer( buffer );
-        if( count == 0 )
-            throw new RuntimeException( "Envelope contained incomplete data:" + env );
+        if( count == 0 ) {
+            // This can happen if there was only a partial message
+            // received.  However, this should never happen for unreliable
+            // connections.
+            if( !reliable ) {
+                // Log some additional information about the packet.
+                int len = Math.min( 10, data.length );
+                StringBuilder sb = new StringBuilder();
+                for( int i = 0; i < len; i++ ) {
+                    sb.append( "[" + Integer.toHexString(data[i]) + "]" ); 
+                }
+                log.log( Level.INFO, "First 10 bytes of incomplete nessage:" + sb );         
+                throw new RuntimeException( "Envelope contained incomplete data:" + env );
+            }                
+        }            
         
         // Should be complete... and maybe we should check but we don't
         Message m = null;