Updated Java client to conform to new API.

- Now uses a single socket.
 - Constructor parameter reordered to match C client.
 - Defaults to an OS assigned port instead of 49008.
This commit is contained in:
Jason Watkins
2015-04-17 09:58:01 -07:00
parent 5ee49c7d81
commit ccc87f06f2
2 changed files with 39 additions and 53 deletions

View File

@@ -44,8 +44,7 @@ import java.util.Arrays;
public class XPlaneConnect implements AutoCloseable public class XPlaneConnect implements AutoCloseable
{ {
private static int clientNum; private static int clientNum;
private DatagramSocket outSocket; private DatagramSocket socket;
private DatagramSocket inSocket;
private InetAddress xplaneAddr; private InetAddress xplaneAddr;
private int xplanePort; private int xplanePort;
@@ -54,7 +53,7 @@ public class XPlaneConnect implements AutoCloseable
* *
* @return The incoming port number. * @return The incoming port number.
*/ */
public int getRecvPort() { return inSocket.getLocalPort(); } public int getRecvPort() { return socket.getLocalPort(); }
/** /**
* Gets the port on which the client sends data to X-Plane. * Gets the port on which the client sends data to X-Plane.
@@ -116,46 +115,44 @@ public class XPlaneConnect implements AutoCloseable
*/ */
public XPlaneConnect(int timeout) throws SocketException public XPlaneConnect(int timeout) throws SocketException
{ {
this.inSocket = new DatagramSocket(49008); this.socket = new DatagramSocket(0);
this.outSocket = new DatagramSocket(50000 + ++clientNum);
this.xplaneAddr = InetAddress.getLoopbackAddress(); this.xplaneAddr = InetAddress.getLoopbackAddress();
this.xplanePort = 49009; this.xplanePort = 49009;
this.inSocket.setSoTimeout(timeout); this.socket.setSoTimeout(timeout);
} }
/** /**
* Initializes a new instance of the {@code XPlaneConnect} class using the specified ports and X-Plane host. * Initializes a new instance of the {@code XPlaneConnect} class using the specified ports and X-Plane host.
* *
* @param port The port on which the X-Plane Connect plugin is sending data. * @param port The port on which the X-Plane Connect plugin is sending data.
* @param xplaneHost The network host on which X-Plane is running. * @param xpHost The network host on which X-Plane is running.
* @param xplanePort The port on which the X-Plane Connect plugin is listening. * @param xpPort The port on which the X-Plane Connect plugin is listening.
* @throws java.net.SocketException If this instance is unable to bind to the specified port. * @throws java.net.SocketException If this instance is unable to bind to the specified port.
* @throws java.net.UnknownHostException If the specified hostname can not be resolved. * @throws java.net.UnknownHostException If the specified hostname can not be resolved.
*/ */
public XPlaneConnect(int port, String xplaneHost, int xplanePort) public XPlaneConnect(String xpHost, int xpPort, int port)
throws java.net.SocketException, java.net.UnknownHostException throws java.net.SocketException, java.net.UnknownHostException
{ {
this(port, xplaneHost, xplanePort, 100); this(xpHost, xpPort, port, 100);
} }
/** /**
* Initializes a new instance of the {@code XPlaneConnect} class using the specified ports, hostname, and timeout. * Initializes a new instance of the {@code XPlaneConnect} class using the specified ports, hostname, and timeout.
* *
* @param port The port on which the X-Plane Connect plugin is sending data. * @param port The port on which the X-Plane Connect plugin is sending data.
* @param xplaneHost The network host on which X-Plane is running. * @param xpHost The network host on which X-Plane is running.
* @param xplanePort The port on which the X-Plane Connect plugin is listening. * @param xpPort The port on which the X-Plane Connect plugin is listening.
* @param timeout The time, in milliseconds, after which read attempts will timeout. * @param timeout The time, in milliseconds, after which read attempts will timeout.
* @throws java.net.SocketException If this instance is unable to bind to the specified port. * @throws java.net.SocketException If this instance is unable to bind to the specified port.
* @throws java.net.UnknownHostException If the specified hostname can not be resolved. * @throws java.net.UnknownHostException If the specified hostname can not be resolved.
*/ */
public XPlaneConnect(int port, String xplaneHost, int xplanePort, int timeout) public XPlaneConnect(String xpHost, int xpPort, int port, int timeout)
throws java.net.SocketException, java.net.UnknownHostException throws java.net.SocketException, java.net.UnknownHostException
{ {
this.inSocket = new DatagramSocket(port); this.socket = new DatagramSocket(port);
this.outSocket = new DatagramSocket(50000 + ++clientNum); this.xplaneAddr = InetAddress.getByName(xpHost);
this.xplaneAddr = InetAddress.getByName(xplaneHost); this.xplanePort = xpPort;
this.xplanePort = xplanePort; this.socket.setSoTimeout(timeout);
this.inSocket.setSoTimeout(timeout);
} }
/** /**
@@ -163,15 +160,10 @@ public class XPlaneConnect implements AutoCloseable
*/ */
public void close() public void close()
{ {
if(inSocket != null) if(socket != null)
{ {
inSocket.close(); socket.close();
inSocket = null; socket = null;
}
if(outSocket != null)
{
outSocket.close();
outSocket = null;
} }
} }
@@ -181,13 +173,13 @@ public class XPlaneConnect implements AutoCloseable
* @return The data send from X-Plane. * @return The data send from X-Plane.
* @throws IOException If the read operation fails * @throws IOException If the read operation fails
*/ */
private byte[] readUDP() throws IOException //TODO: Store data in a class level buffer to account for partial messages private byte[] readUDP() throws IOException
{ {
byte[] buffer = new byte[2048]; byte[] buffer = new byte[2048];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length); DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
try try
{ {
inSocket.receive(packet); socket.receive(packet);
return Arrays.copyOf(buffer, buffer[4]); return Arrays.copyOf(buffer, buffer[4]);
} }
catch (SocketTimeoutException ex) catch (SocketTimeoutException ex)
@@ -212,7 +204,7 @@ public class XPlaneConnect implements AutoCloseable
buffer[4] = (byte)buffer.length; buffer[4] = (byte)buffer.length;
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, xplaneAddr, xplanePort); DatagramPacket packet = new DatagramPacket(buffer, buffer.length, xplaneAddr, xplanePort);
outSocket.send(packet); socket.send(packet);
} }
/** /**
@@ -672,12 +664,12 @@ public class XPlaneConnect implements AutoCloseable
/** /**
* Sets the port on which the client will receive data from X-Plane. * Sets the port on which the client will receive data from X-Plane.
* *
* @param recvPort The new incoming port number. * @param port The new incoming port number.
* @throws IOException If the command cannnot be sent. * @throws IOException If the command cannnot be sent.
*/ */
public void setCONN(int recvPort) throws IOException public void setCONN(int port) throws IOException
{ {
if(recvPort < 0 || recvPort >= 0xFFFF) if(port < 0 || port >= 0xFFFF)
{ {
throw new IllegalArgumentException("Invalid port (must be non-negative and less than 65536)."); throw new IllegalArgumentException("Invalid port (must be non-negative and less than 65536).");
} }
@@ -685,14 +677,14 @@ public class XPlaneConnect implements AutoCloseable
ByteArrayOutputStream os = new ByteArrayOutputStream(); ByteArrayOutputStream os = new ByteArrayOutputStream();
os.write("CONN".getBytes(StandardCharsets.UTF_8)); os.write("CONN".getBytes(StandardCharsets.UTF_8));
os.write(0xFF); //Placeholder for message length os.write(0xFF); //Placeholder for message length
os.write((byte) recvPort); os.write((byte) port);
os.write((byte) (recvPort >> 8)); os.write((byte) (port >> 8));
sendUDP(os.toByteArray()); sendUDP(os.toByteArray());
int soTimeout = inSocket.getSoTimeout(); int soTimeout = socket.getSoTimeout();
inSocket.close(); socket.close();
inSocket = new DatagramSocket(recvPort); socket = new DatagramSocket(port);
inSocket.setSoTimeout(soTimeout); socket.setSoTimeout(soTimeout);
readUDP(); // Try to read response readUDP(); // Try to read response
} }
} }

View File

@@ -31,7 +31,7 @@ public class XPlaneConnectTest
{ {
fail(); fail();
} }
try(XPlaneConnect xpc = new XPlaneConnect(49007, "127.0.0.1", 49009)) try(XPlaneConnect xpc = new XPlaneConnect("127.0.0.1", 49009, 49007))
{ {
assertNotNull(xpc); assertNotNull(xpc);
} }
@@ -39,7 +39,7 @@ public class XPlaneConnectTest
{ {
fail(); fail();
} }
try(XPlaneConnect xpc = new XPlaneConnect(49007, "127.0.0.1", 49009, 200)) try(XPlaneConnect xpc = new XPlaneConnect("127.0.0.1", 49009, 49007, 200))
{ {
assertNotNull(xpc); assertNotNull(xpc);
} }
@@ -50,9 +50,9 @@ public class XPlaneConnectTest
} }
@Test @Test
public void testGetRecvPort() throws SocketException public void testGetRecvPort() throws Exception
{ {
try(XPlaneConnect xpc = new XPlaneConnect()) try(XPlaneConnect xpc = new XPlaneConnect("127.0.0.1", 49009, 49008))
{ {
assertEquals(49008, xpc.getRecvPort()); assertEquals(49008, xpc.getRecvPort());
} }
@@ -87,11 +87,11 @@ public class XPlaneConnectTest
} }
@Test @Test
public void constructorTest_SocketAlreadyBound() throws SocketException public void constructorTest_SocketAlreadyBound() throws Exception
{ {
try(XPlaneConnect xpc = new XPlaneConnect()) try(XPlaneConnect xpc = new XPlaneConnect("127.0.0.1", 49009, 49008))
{ {
try(XPlaneConnect xpc2 = new XPlaneConnect()) try(XPlaneConnect xpc2 = new XPlaneConnect("127.0.0.1", 49009, 49008))
{ {
fail(); fail();
} }
@@ -106,7 +106,7 @@ public class XPlaneConnectTest
@Test(expected = UnknownHostException.class) @Test(expected = UnknownHostException.class)
public void constructorTest_InvalidHost() throws UnknownHostException public void constructorTest_InvalidHost() throws UnknownHostException
{ {
try(XPlaneConnect xpc = new XPlaneConnect(49007, "notarealhost", 49009)) try(XPlaneConnect xpc = new XPlaneConnect("notarealhost", 49009, 49007))
{ {
} }
@@ -575,16 +575,10 @@ public class XPlaneConnectTest
String dref = "sim/cockpit/switches/gear_handle_status"; String dref = "sim/cockpit/switches/gear_handle_status";
try(XPlaneConnect xpc = new XPlaneConnect()) try(XPlaneConnect xpc = new XPlaneConnect())
{ {
int p = xpc.getRecvPort();
xpc.setCONN(49055); xpc.setCONN(49055);
assertEquals(49055, xpc.getRecvPort()); assertEquals(49055, xpc.getRecvPort());
float[] result = xpc.requestDREF(dref); float[] result = xpc.requestDREF(dref);
assertEquals(1, result.length); assertEquals(1, result.length);
xpc.setCONN(p);
assertEquals(p, xpc.getRecvPort());
result = xpc.requestDREF(dref);
assertEquals(1, result.length);
} }
} }