1

我正在开发 2 个必须使用蓝牙和 WiFi P2P 以 JSON 格式交换某种数据的 Android 应用程序。

蓝牙部分进展顺利,一切正常。

问题出现在 WiFi P2P 实现中,因为我无法连接套接字以交换数据。这些设备使用 WiFi-P2P 连接良好,但问题在于 Socket 编程级别。

我没有收到任何错误消息,但 ServerSocket 从未收到连接请求。我已经检查过,来自服务器应用程序端的 ServerSocket 和来自客户端应用程序端的 Socket 都绑定到相同的 IP 地址:192.168.49.1 端口 8989。

任何有关我的代码可能有问题的帮助将不胜感激。

这是作为服务器的应用程序上的代码:

public class WiFiIO {

private static final String LOG = "UJUKE-CONTROLLER-WIFI-IO";

public static int SERVER_PORT = 8989;
public String IP = "";

private final Handler mHandler;

private AcceptThread mAcceptThread;
private ConnectedThread mConnectedThread;
private int mState;

// Constants that indicate the current connection state
public static final int STATE_NONE = 0;       // we're doing nothing
public static final int STATE_LISTEN = 1;     // now listening for incoming connections
public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
public static final int STATE_CONNECTED = 3;  // now connected to a remote device

// Message types sent from the BluetoothChatService Handler
public static final int MESSAGE_STATE_CHANGE = 1;
public static final int MESSAGE_READ = 2;
public static final int MESSAGE_WRITE = 3;
public static final int MESSAGE_DEVICE_NAME = 4;
public static final int MESSAGE_TOAST = 5;

// Key names received from the BluetoothChatService Handler
public static final String DEVICE_NAME = "device_name";
public static final String TOAST = "toast";


/**
 * Constructor. Prepares a new WiFi session.
 *
 * @param context The UI Activity Context
 * @param handler A Handler to send messages back to the UI Activity
 */
public WiFiIO(Context context, 
            Handler handler) {       
    mState = STATE_NONE;
    mHandler = handler;
}

/**
 * Set the current state of the chat connection
 *
 * @param state An integer defining the current connection state
 */
private synchronized void setState(int state) {
    Log.d(LOG, "setState() " + mState + " -> " + state);
    mState = state;

    // Give the new state to the Handler so the UI Activity can update
    mHandler.obtainMessage(MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
}

/**
 * Return the current connection state.
 */
public synchronized int getState() {
    return mState;
}

/**
 * Start the lisen service. Specifically start AcceptThread to begin a
 * session in listening (server) mode. Called by the Activity onResume()
 */
public synchronized void start(String ip) {
    Log.d(LOG, "start");

   IP = ip;

    // Cancel any thread currently running a connection
    if (mConnectedThread != null) {
        mConnectedThread.cancel();
        mConnectedThread = null;
    }

    setState(STATE_LISTEN);

    // Start the thread to listen on a ServerSocket
    if (mAcceptThread == null) {
        mAcceptThread = new AcceptThread();
        mAcceptThread.start();
    }
}

/**
 * Start the ConnectedThread to begin managing a wi-fi connection
 *
 */
public synchronized void connected(Socket socket) {
    //Log.d(LOG, "connected to " + mConfig.deviceAddress);
    Log.d(LOG, "connected");

    // Cancel any thread currently running a connection
    if (mConnectedThread != null) {
        mConnectedThread.cancel();
        mConnectedThread = null;
    }

    // Cancel the accept thread because we only want to connect to one device
    if (mAcceptThread != null) {
        mAcceptThread.cancel();
        mAcceptThread = null;
    }

    // Start the thread to manage the connection and perform transmissions
    mConnectedThread = new ConnectedThread(socket, socket.getRemoteSocketAddress());
    mConnectedThread.start();

    // Send the name of the connected device back to the UI Activity
    Message msg = mHandler.obtainMessage(MESSAGE_DEVICE_NAME);
    Bundle bundle = new Bundle();
    bundle.putString(DEVICE_NAME, "device");
    msg.setData(bundle);
    mHandler.sendMessage(msg);
}


/**
 * Stop all threads
 */
public synchronized void stop() {
    Log.d(LOG, "stop");

    if (mConnectedThread != null) {
        mConnectedThread.cancel();
        mConnectedThread = null;
    }

    if (mAcceptThread != null) {
        mAcceptThread.cancel();
        mAcceptThread = null;
    }
    setState(STATE_NONE);
}

/**
 * Write to the ConnectedThread in an unsynchronized manner
 *
 * @param out The bytes to write
 * @see ConnectedThread#write(byte[])
 */
public void write(byte[] out) {
    // Create temporary object
    ConnectedThread r;
    // Synchronize a copy of the ConnectedThread
    synchronized (this) {
        if (mState != STATE_CONNECTED) return;
        r = mConnectedThread;
    }
    // Perform the write unsynchronized
    r.write(out);
}

/**
 * Indicate that the connection was lost and notify the UI Activity.
 */
private void connectionLost() {     
    // Send a failure message back to the Activity
    Message msg = mHandler.obtainMessage(MESSAGE_TOAST);
    Bundle bundle = new Bundle();
    bundle.putString(TOAST, "Device connection was lost");
    msg.setData(bundle);
    mHandler.sendMessage(msg);

    // Start the service over to restart listening mode
    WiFiIO.this.start(IP);
}

/**
 * This thread runs while listening for incoming connections. It behaves
 * like a server-side client. It runs until a connection is accepted
 * (or until cancelled).
 */
private class AcceptThread extends Thread {
    // The local server socket
    private final ServerSocket mmServerSocket;

    public AcceptThread() {
        ServerSocket tmp = null;

        // Create a new listening server socket
        try {
                tmp  = new ServerSocket(SERVER_PORT);
                //tmp  = new ServerSocket(SERVER_PORT,50,InetAddress.getByName(IP)); 
        } catch (IOException e) {
            Log.e(LOG, "Socket listen() failed", e);
        }
        mmServerSocket = tmp;
    }

    public void run() {
        Log.d(LOG, "Socket BEGIN mAcceptThread" + this);
        setName("AcceptThread");

        Socket socket = null;

        // Listen to the server socket if we're not connected
        while (mState != STATE_CONNECTED) {
            try {
                // This is a blocking call and will only return on a
                // successful connection or an exception                    
                Log.e(LOG, "Socket server bonded to ip" + mmServerSocket.getInetAddress().toString());
                socket = mmServerSocket.accept();
            } catch (IOException e) {
                Log.e(LOG, "Socket Type  accept() failed", e);
                //break;
            }

            // If a connection was accepted
            if (socket != null) {
                synchronized (WiFiIO.this) {
                    switch (mState) {
                        case STATE_LISTEN:
                        case STATE_CONNECTING:
                            // Situation normal. Start the connected thread.
                            connected(socket);
                            break;
                        case STATE_NONE:
                        case STATE_CONNECTED:
                            // Either not ready or already connected. Terminate new socket.
                            try {
                                socket.close();
                            } catch (IOException e) {
                                Log.e(LOG, "Could not close unwanted socket", e);
                            }
                            break;
                    }
                }
            }
        }
        Log.i(LOG, "END mAcceptThread, socket Type");

    }

    public void cancel() {
        Log.d(LOG, "Socket Type cancel " + this);
        try {
            mmServerSocket.close();
        } catch (IOException e) {
            Log.e(LOG, "Socket Type close() of server failed", e);
        }
    }
}

/**
 * This thread runs during a connection with a remote device.
 * It handles all incoming and outgoing transmissions.
 */
private class ConnectedThread extends Thread {
    private final Socket mmSocket;
    private final InputStream mmInStream;
    private final OutputStream mmOutStream;

    public ConnectedThread(Socket socket, SocketAddress address) {
        Log.d(LOG, "create ConnectedThread: ");
        mmSocket = socket;
        InputStream tmpIn = null;
        OutputStream tmpOut = null;

        // Get the BluetoothSocket input and output streams
        try {
            tmpIn = socket.getInputStream();
            tmpOut = socket.getOutputStream();
        } catch (IOException e) {
            Log.e(LOG, "temp sockets not created", e);
        }

        mmInStream = tmpIn;
        mmOutStream = tmpOut;
    }

    public void run() {
        Log.i(LOG, "BEGIN mConnectedThread");
        byte[] buffer = new byte[1024];
        int bytes;

        // Keep listening to the InputStream while connected
        while (true) {
            try {
                int timeout = 0;
                int maxTimeout = 32; // leads to a timeout of 2 seconds
                int available = 0;

                while((available = mmInStream.available()) == 0 && timeout < maxTimeout) {
                    timeout++;
                    // throws interrupted exception
                    try {
                        Thread.sleep(250);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                // Read from the InputStream
                buffer = new byte[available];
                bytes = mmInStream.read(buffer);

                // Send the obtained bytes to the UI Activity
                mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
                        .sendToTarget();
            } catch (IOException e) {
                Log.e(LOG, "disconnected", e);
                connectionLost();
                // Start the service over to restart listening mode
                WiFiIO.this.start(IP);
                break;
            }
        }
    }

    /**
     * Write to the connected OutStream.
     *
     * @param buffer The bytes to write
     */
    public void write(byte[] buffer) {
        try {
            //mmOutStream.write(buffer);
            mmOutStream.write(buffer,0,buffer.length);
            mmOutStream.flush();
            // Share the sent message back to the UI Activity
            mHandler.obtainMessage(MESSAGE_WRITE, -1, -1, buffer)
                    .sendToTarget();
        } catch (IOException e) {
            Log.e(LOG, "Exception during write", e);
        }
    }

    public void cancel() {
        try {
            mmOutStream.close();
            mmInStream.close();
            mmSocket.close();
        } catch (IOException e) {
            Log.e(LOG, "close() of connect socket failed", e);
        }
    }
}

}

这是作为客户端的应用程序上的代码:

public class WiFiIO {

private static final String LOG = "UJUKE-CONTROLLER-WIFI-IO";

public static int SERVER_PORT = 8989;

private final Handler mHandler;

private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
private int mState;

// Constants that indicate the current connection state
public static final int STATE_NONE = 0;       // we're doing nothing
public static final int STATE_LISTEN = 1;     // now listening for incoming connections
public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
public static final int STATE_CONNECTED = 3;  // now connected to a remote device

// Message types sent from the BluetoothChatService Handler
public static final int MESSAGE_STATE_CHANGE = 1;
public static final int MESSAGE_READ = 2;
public static final int MESSAGE_WRITE = 3;
public static final int MESSAGE_DEVICE_NAME = 4;
public static final int MESSAGE_TOAST = 5;

// Key names received from the BluetoothChatService Handler
public static final String DEVICE_NAME = "device_name";
public static final String TOAST = "toast";

/**
 * Constructor. Prepares a new WiFi session.
 *
 * @param context The UI Activity Context
 * @param handler A Handler to send messages back to the UI Activity
 */
public WiFiIO(Handler handler) {
    mState = STATE_NONE;
    mHandler = handler;
}

/**
 * Set the current state of the chat connection
 *
 * @param state An integer defining the current connection state
 */
private synchronized void setState(int state) {
    Log.d(LOG, "setState() " + mState + " -> " + state);
    mState = state;

    // Give the new state to the Handler so the UI Activity can update
    mHandler.obtainMessage(MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
}

/**
 * Return the current connection state.
 */
public synchronized int getState() {
    return mState;
}

/**
 * Start the ConnectThread to initiate a connection to a remote device.
 *
 * @param device The IP address to connect
 */
public synchronized void connect(String ip) {
    Log.d(LOG, "connect to: " + ip);

    // Cancel any thread attempting to make a connection
    if (mState == STATE_CONNECTING) {
        if (mConnectThread != null) {
            mConnectThread.cancel();
            mConnectThread = null;
        }
    }

    // Cancel any thread currently running a connection
    if (mConnectedThread != null) {
        mConnectedThread.cancel();
        mConnectedThread = null;
    }

    // Start the thread to connect with the given device
    mConnectThread = new ConnectThread(ip);
    mConnectThread.start();
    setState(STATE_CONNECTING);
}

/**
 * Start the ConnectedThread to begin managing a WiFi connection
 *
 * @param socket The Socket on which the connection was made
 */
public synchronized void connected(Socket socket) {
    Log.d(LOG, "connected, Socket Type");

    // Cancel the thread that completed the connection
    if (mConnectThread != null) {
        mConnectThread.cancel();
        mConnectThread = null;
    }

    // Cancel any thread currently running a connection
    if (mConnectedThread != null) {
        mConnectedThread.cancel();
        mConnectedThread = null;
    }

    // Start the thread to manage the connection and perform transmissions
    mConnectedThread = new ConnectedThread(socket);
    mConnectedThread.start();

    // Send the name of the connected device back to the UI Activity
    Message msg = mHandler.obtainMessage(MESSAGE_DEVICE_NAME);
    Bundle bundle = new Bundle();
    bundle.putString(DEVICE_NAME, socket.getRemoteSocketAddress().toString());
    msg.setData(bundle);
    mHandler.sendMessage(msg);

    setState(STATE_CONNECTED);
}

/**
 * Stop all threads
 */
public synchronized void stop() {
    Log.d(LOG, "stop");

    if (mConnectThread != null) {
        mConnectThread.cancel();
        mConnectThread = null;
    }

    if (mConnectedThread != null) {
        mConnectedThread.cancel();
        mConnectedThread = null;
    }

    setState(STATE_NONE);
}

/**
 * Write to the ConnectedThread in an unsynchronized manner
 *
 * @param out The bytes to write
 * @see ConnectedThread#write(byte[])
 */
public void write(byte[] out) {
    // Create temporary object
    ConnectedThread r;
    // Synchronize a copy of the ConnectedThread
    synchronized (this) {
        if (mState != STATE_CONNECTED) return;
        r = mConnectedThread;
    }
    // Perform the write unsynchronized
    r.write(out);
}

/**
 * Indicate that the connection attempt failed and notify the UI Activity.
 */
private void connectionFailed() {
    setState(STATE_NONE);
    // Send a failure message back to the Activity
    Message msg = mHandler.obtainMessage(MESSAGE_TOAST);
    Bundle bundle = new Bundle();
    bundle.putString(TOAST, "Unable to connect device");
    msg.setData(bundle);
    mHandler.sendMessage(msg);
}

/**
 * Indicate that the connection was lost and notify the UI Activity.
 */
private void connectionLost() {
    // Send a failure message back to the Activity
    Message msg = mHandler.obtainMessage(MESSAGE_TOAST);
    Bundle bundle = new Bundle();
    bundle.putString(TOAST, "Device connection was lost");
    msg.setData(bundle);
    mHandler.sendMessage(msg);
}

/**
 * This thread runs while attempting to make an outgoing connection
 * with a device. It runs straight through; the connection either
 * succeeds or fails.
 */
private class ConnectThread extends Thread {
    private final Socket mmSocket;
    private final String mmIP;

    public ConnectThread(String ip) {
        Socket tmp = null;

        // Get a Socket for a connection with the
        // given ip
        //try {
                tmp = new Socket();
        //} catch (IOException e) {
          //  Log.e(LOG, "Socket Type: create() failed", e);
        //}
        mmSocket = tmp;
        mmIP = ip;
    }

    public void run() {
        Log.i(LOG, "BEGIN mConnectThread ");
        setName("ConnectThread");

        // Make a connection to the ServerSocket
        try {
            // This is a blocking call and will only return on a
            // successful connection or an exception
            while(mmSocket.isConnected() == false){
                try{
                    mmSocket.bind(null);
                    mmSocket.connect((new InetSocketAddress(mmIP, SERVER_PORT)),0);
                }catch (IOException e) {
                    Log.e(LOG, "unable to connect to server socket", e);
                }
            }
        } catch (Exception e) {
            // Close the socket
            try {
                mmSocket.close();
            } catch (IOException e2) {
                Log.e(LOG, "unable to close()  socket during connection failure", e2);
            }
            connectionFailed();
            return;
        }

        // Reset the ConnectThread because we're done
        synchronized (WiFiIO.this) {
            mConnectThread = null;
        }

        // Start the connected thread
        connected(mmSocket);
    }

    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) {
            Log.e(LOG, "close() of connect socket failed", e);
        }
    }
}

/**
 * This thread runs during a connection with a remote device.
 * It handles all incoming and outgoing transmissions.
 */
private class ConnectedThread extends Thread {
    private final Socket mmSocket;
    private final InputStream mmInStream;
    private final OutputStream mmOutStream;

    public ConnectedThread(Socket socket) {
        Log.d(LOG, "create ConnectedThread");
        mmSocket = socket;
        InputStream tmpIn = null;
        OutputStream tmpOut = null;

        // Get the Socket input and output streams
        try {
            tmpIn = socket.getInputStream();
            tmpOut = socket.getOutputStream();
        } catch (IOException e) {
            Log.e(LOG, "temp sockets not created", e);
        }

        mmInStream = tmpIn;
        mmOutStream = tmpOut;
        if(mmOutStream != null){
            String s = "start";
            write(s.getBytes());
        }
    }

    public void run() {
        Log.i(LOG, "BEGIN mConnectedThread");
        byte[] buffer = new byte[1024];
        int bytes;

        // Keep listening to the InputStream while connected
        while (true) {
            try {
                int timeout = 0;
                int maxTimeout = 32; // leads to a timeout of 2 seconds
                int available = 0;

                while((available = mmInStream.available()) == 0 && timeout < maxTimeout) {
                    timeout++;
                    // throws interrupted exception
                    try {
                        Thread.sleep(250);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }

                // Read from the InputStream
                buffer = new byte[available];
                bytes = mmInStream.read(buffer);

                // Send the obtained bytes to the UI Activity
                mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
                        .sendToTarget();
            } catch (IOException e) {
                Log.e(LOG, "disconnected", e);
                connectionLost();
                break;
            }
        }
    }

    /**
     * Write to the connected OutStream.
     *
     * @param buffer The bytes to write
     */
    public void write(byte[] buffer) {
        try {
            mmOutStream.write(buffer);
            mmOutStream.flush();
            // Share the sent message back to the UI Activity
            mHandler.obtainMessage(MESSAGE_WRITE, -1, -1, buffer)
                    .sendToTarget();
        } catch (IOException e) {
            Log.e(LOG, "Exception during write", e);
        }
    }

    public void cancel() {
        try {
            mmOutStream.close();
            mmInStream.close();
            mmSocket.close();                
        } catch (IOException e) {
            Log.e(LOG, "close() of connect socket failed", e);
        }
    }
}

}

4

0 回答 0