Browse Source

UDP-based kernel now does its writes on a background
thread. Most of the time UDP packets go right out
but not always... depending on the network layer it can
take a couple of milliseconds. And that's alot when
you're blasting packets out to a dozen users 20 times
a second.


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

PSp..om 14 năm trước cách đây
mục cha
commit
593d9bf35a

+ 8 - 1
engine/src/networking/com/jme3/network/kernel/udp/UdpEndpoint.java

@@ -114,10 +114,17 @@ public class UdpEndpoint implements Endpoint
         if( !isConnected() ) {
         if( !isConnected() ) {
             throw new KernelException( "Endpoint is not connected:" + this );
             throw new KernelException( "Endpoint is not connected:" + this );
         }
         }
+        
+        
         try {
         try {
             DatagramPacket p = new DatagramPacket( data.array(), data.position(), 
             DatagramPacket p = new DatagramPacket( data.array(), data.position(), 
                                                    data.remaining(), address );
                                                    data.remaining(), address );
-            socket.send(p);
+                                                   
+            // Just queue it up for the kernel threads to write
+            // out
+            kernel.enqueueWrite( this, p );
+                                                               
+            //socket.send(p);
         } catch( IOException e ) {
         } catch( IOException e ) {
             throw new KernelException( "Error sending datagram to:" + address, e );
             throw new KernelException( "Error sending datagram to:" + address, e );
         }
         }

+ 46 - 2
engine/src/networking/com/jme3/network/kernel/udp/UdpKernel.java

@@ -37,6 +37,8 @@ import java.net.*;
 import java.nio.ByteBuffer;
 import java.nio.ByteBuffer;
 import java.util.*;
 import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.logging.Level;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
@@ -57,6 +59,8 @@ public class UdpKernel extends AbstractKernel
     private InetSocketAddress address;
     private InetSocketAddress address;
     private HostThread thread;
     private HostThread thread;
 
 
+    private ExecutorService writer = Executors.newFixedThreadPool(2);
+    
     // The nature of UDP means that even through a firewall,
     // The nature of UDP means that even through a firewall,
     // a user would have to have a unique address+port since UDP
     // a user would have to have a unique address+port since UDP
     // can't really be NAT'ed.
     // can't really be NAT'ed.
@@ -104,6 +108,7 @@ public class UdpKernel extends AbstractKernel
 
 
         try {
         try {
             thread.close();
             thread.close();
+            writer.shutdown();
             thread = null;
             thread = null;
         } catch( IOException e ) {
         } catch( IOException e ) {
             throw new KernelException( "Error closing host connection:" + address, e );
             throw new KernelException( "Error closing host connection:" + address, e );
@@ -120,8 +125,13 @@ public class UdpKernel extends AbstractKernel
         if( reliable )
         if( reliable )
             throw new UnsupportedOperationException( "Reliable send not supported by this kernel." );
             throw new UnsupportedOperationException( "Reliable send not supported by this kernel." );
 
 
-        // We ignore the copy flag because we know all outbound traffic
-        // goes instantly.
+        if( copy )
+            {
+            // Copy the data just once
+            byte[] temp = new byte[data.remaining()];
+            System.arraycopy(data.array(), data.position(), temp, 0, data.remaining());
+            data = ByteBuffer.wrap(temp);
+            }
 
 
         // Hand it to all of the endpoints that match our routing
         // Hand it to all of the endpoints that match our routing
         for( UdpEndpoint p : socketEndpoints.values() ) {
         for( UdpEndpoint p : socketEndpoints.values() ) {
@@ -177,6 +187,40 @@ public class UdpKernel extends AbstractKernel
         addEnvelope( env );
         addEnvelope( env );
     }
     }
 
 
+    protected void enqueueWrite( Endpoint endpoint, DatagramPacket packet )
+    {
+        writer.execute( new MessageWriter(endpoint, packet) );
+    } 
+
+    protected class MessageWriter implements Runnable
+    {
+        private Endpoint endpoint;
+        private DatagramPacket packet;
+        
+        public MessageWriter( Endpoint endpoint, DatagramPacket packet )
+        {
+            this.endpoint = endpoint;
+            this.packet = packet;
+        }
+        
+        public void run()
+        {
+            // Not guaranteed to always work but an extra datagram
+            // to a dead connection isn't so big of a deal.
+            if( !endpoint.isConnected() ) {
+                return;
+            }
+            
+            try {
+                thread.getSocket().send(packet);
+            } catch( Exception e ) {
+                KernelException exc = new KernelException( "Error sending datagram to:" + address, e );
+                exc.fillInStackTrace();
+                reportError(exc);
+            }
+        } 
+    }
+
     protected class HostThread extends Thread
     protected class HostThread extends Thread
     {
     {
         private DatagramSocket socket;
         private DatagramSocket socket;