-Added a class to serve up results to atom. A matching client C++ class should follow shortly.
-Generally beautified code
git-svn-id: https://robotics.mvla.net/svn/frc971/2013/trunk/src@4148 f308d9b7-e957-4cde-b6ac-9a88185e7312
diff --git a/971CV/src/org/frc971/AccepterThread.java b/971CV/src/org/frc971/AccepterThread.java
new file mode 100644
index 0000000..e6cd5dd
--- /dev/null
+++ b/971CV/src/org/frc971/AccepterThread.java
@@ -0,0 +1,153 @@
+/**
+ *
+ */
+package org.frc971;
+
+/**
+ * @author daniel
+ * Accepts clients for data server
+ */
+
+import java.io.IOException;
+
+import java.nio.ByteBuffer;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+
+public class AccepterThread extends Thread {
+
+ private final static Logger LOG = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
+
+ private ServerSocketChannel sock;
+
+ private List<SocketChannel> connected = new ArrayList<SocketChannel>();
+
+ /* Holds overflow data when socket's send buffer gets full, so that
+ * thread can continue running.
+ */
+ private Map<SocketChannel, ByteBuffer> toSend;
+ /* Keeps track of how many times a write operation on a socket
+ * has failed because it's buffer was full.
+ */
+ private Map<SocketChannel, Integer> failedAttempts; //doesn't like primitive types
+
+ /** Helper function to completely erase a peer from
+ * all three lists and maps that might contain it.
+ */
+ private void erasePeer(SocketChannel peer) {
+ connected.remove(peer);
+ toSend.remove(peer);
+ failedAttempts.remove(peer);
+ }
+
+ /** Constructor
+ *
+ * @param sock is the ServerSocketChannel that you want to monitor
+ */
+ public AccepterThread(ServerSocketChannel sock) {
+ super("Accepter Thread");
+ setPriority(3); //lowish priority so Image Processor overrides it
+ this.sock = sock;
+ start();
+ }
+
+ /** Runs in separate thread. Continually accepts new connections. */
+ public void run() {
+ SocketChannel clientSock;
+ while (true) {
+ try {
+ clientSock = sock.accept();
+ //our writes must not block
+ clientSock.configureBlocking(false);
+ connected.add(clientSock);
+ }
+ catch (IOException e) {
+ LOG.warning("Socket accept failed.");
+ }
+ }
+ }
+
+ /** Sends a message to all currently connected clients.
+ *
+ * @param message is the message that you want to send.
+ */
+ public void sendtoAll(ByteBuffer message) {
+ /* Copy our connected list, so we don't have
+ * to hold our lock forever if the writes block.
+ */
+ List<SocketChannel> connectedTemp = new ArrayList<SocketChannel>();
+ for (SocketChannel channel : connected) {
+ connectedTemp.add(channel);
+ }
+
+ int result;
+ for (SocketChannel conn : connectedTemp) {
+ try {
+
+ /** If this socket has data from the
+ * last send operation still waiting to be
+ * sent, send this instead of our original
+ * message. Since we generally want only
+ * current data, our original message will
+ * not be missed. However, it is imperative
+ * that we finish our pending transmission,
+ * because an incomplete transmission could
+ * leave a client thread somewhere blocking
+ * indefinitely.
+ */
+ if (toSend.containsKey(conn)) {
+ message = toSend.get(conn);
+ }
+
+ result = conn.write(message);
+
+ /*if our send buffer is full, store our message away
+ * so we can try again later without halting the thread.
+ */
+ if (message.remaining() > 0) {
+ toSend.put(conn, message);
+ //check and update our count of failed send attempts
+ if (failedAttempts.containsKey(conn)) {
+ int failures = failedAttempts.get(conn);
+ ++failures;
+ if (failures >= 100) {
+ //Socket has become dysfunctional
+ LOG.info("Write would have blocked 100 times. Assuming peer disconect.");
+ erasePeer(conn);
+ }
+ failedAttempts.put(conn, failures);
+ }
+ else {
+ failedAttempts.put(conn, 1);
+ }
+ }
+
+ if (result == -1) {
+ //The write failed. This is probably because the client disconnected.
+ LOG.info("Write returned -1. Client has probably disconnected.");
+ erasePeer(conn);
+ }
+ }
+ catch (IOException e) {
+ //The write failed. This is probably because the client disconnected.
+ LOG.info("Write threw IOException. Client has probably disconnected.");
+ erasePeer(conn);
+ }
+ }
+ }
+
+ /** Overloaded sendtoAll method for byte arrays. */
+ public void sendtoAll(byte[] message) {
+ sendtoAll(ByteBuffer.wrap(message));
+ }
+
+ /** Overloaded sendtoAll method for Strings. */
+ public void sendtoAll(String message) {
+ sendtoAll(message.getBytes());
+ }
+}