📄 client.java
字号:
/* The Bluetooth Library for client-server communication Copyright (C) 2006 Martin Vysny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */package net.sf.btw.btlib;import java.io.ByteArrayInputStream;import java.io.DataInputStream;import javax.bluetooth.L2CAPConnection;import javax.bluetooth.UUID;import net.sf.btw.tools.Logger;/** * <p> * A client helper class that will attempt to connect to the server. Not thread * safe. You can only connect to a single server per one client class instance. * </p> * <p> * Please follow these steps: * </p> * <ul> * <li>Create instance of the object</li> * <li>set {@link #listener}</li> * <li>{@link #connect(ServerInfo) connect} to a single server</li> * <li>{@link #send(byte[]) send} data to server, receive data via the listener</li> * <li>{@link #disconnect()} from the server</li> * </ul> * * @author Martin Vysny * */public final class Client extends Peer implements Runnable, IErrorListener { /** * Starts acting as a client. * * @param server * server ID * @param receiveMTU * maximum size of received packet, see * {@link L2CAPConnection#getReceiveMTU()} for details. * @param transmitMTU * maximum size of transmitted packet, see * {@link L2CAPConnection#getTransmitMTU()} for details. * @param listener * Listens for client events. Must not be <code>null</code> */ public Client(final UUID server, final int receiveMTU, final int transmitMTU, final IClientListener listener) { super(server, receiveMTU, transmitMTU, listener); receiverBuffer = new byte[receiveMTU]; } /** * Tries to connect to given server. The function does not block and returns * immediately. * * @param server * server to connect. */ public void connect(final ServerInfo server) { checkNotConnected(); this.server = server; new Thread(this).start(); } /** * We are going to connect to this server. */ private volatile ServerInfo server; /** * Connection to server. */ private L2CAPConnection connection; private PacketScheduler scheduler; /** * Lock onto this object when a connection state is changing. */ private final Object connectionChangeLock = new Object(); /** * Disconnects from the server. */ public void disconnect() { synchronized (connectionChangeLock) { if (connection != null) { try { scheduler.stop(); connection.close(); connection = null; } catch (Exception e) { Logger.info("Client.disconnect()", e); //$NON-NLS-1$ invokeErrorOccured(SERVER_ID, IErrorListener.ERROR_HINT_CLOSING_CONNECTION, null, e); } try { ((IClientListener) listener).disconnected(); } catch (Exception ex) { invokeErrorOccured(SERVER_ID, IErrorListener.ERROR_HINT_CLOSING_CONNECTION, "disconnected()", ex); //$NON-NLS-1$ } Logger.debug("Client.disconnect(): disconnected", null); //$NON-NLS-1$ } } } private final static Byte ZERO = new Byte((byte)0); /** * Ensures that the client is connected to the server. */ void checkConnected() { if (connection == null) throw new IllegalArgumentException("Client not connected"); //$NON-NLS-1$ } /** * Ensures that the client is not connected to the server. */ void checkNotConnected() { if (connection != null) throw new IllegalArgumentException( "Client connected, disconnect first"); //$NON-NLS-1$ } /** * Received data is placed here. */ private final byte[] receiverBuffer; /** * Internal method, not intended to be called by users. */ public void run() { Logger.debug("Client.run(): starting listener", null); //$NON-NLS-1$ try { try { synchronized (connectionChangeLock) { connection = server.connectToServer(serverId); } scheduler = new PacketScheduler(this); scheduler.addRoute(ZERO, connection); } catch (Exception ex) { Logger.error("Client.run(): connecting", ex); //$NON-NLS-1$ invokeErrorOccured(Peer.SERVER_ID, IErrorListener.ERROR_HINT_OPENING_CONNECTION, null, ex); return; } try { ((IClientListener) listener).connected(server.clientId); } catch (Exception ex) { invokeErrorOccured(SERVER_ID, IErrorListener.ERROR_HINT_OPENING_CONNECTION, "connected()", ex); //$NON-NLS-1$ disconnect(); return; } try { Logger.debug("Client.run(): waiting for data", null); //$NON-NLS-1$ while (true) { final L2CAPConnection conn = connection; if (conn == null) return; final int bytesReceived = conn.receive(receiverBuffer); final DataInputStream stream = new DataInputStream( new ByteArrayInputStream(receiverBuffer, 0, bytesReceived)); // invoke messageArrived handler try { ((IClientListener) listener).messageArrived( receiverBuffer, bytesReceived, stream); } catch (Exception ex) { invokeErrorOccured(SERVER_ID, IErrorListener.ERROR_HINT_COMMUNICATING, "messageArrived()", ex); //$NON-NLS-1$ } } } catch (Exception ex) { // this exception may be invoked by closing a connection in // disconnect() method. Check if this is such a case. boolean isDisconnected = false; synchronized (connectionChangeLock) { isDisconnected = (connection == null); } Logger.log(isDisconnected ? Logger.LEVEL_DEBUG : Logger.LEVEL_ERROR, "Client.run()", ex); //$NON-NLS-1$ if (!isDisconnected) invokeErrorOccured(SERVER_ID, IErrorListener.ERROR_HINT_COMMUNICATING, null, ex); } disconnect(); } finally { Logger.debug("Client.run(): terminating", null); //$NON-NLS-1$ } } /** * Sends given byte array to server. Does not block. * * @param data * the data to send. You must not modify the array until the * message get sent. */ public void send(byte[] data) { scheduler.sendPacket(ZERO, data); } /** * Internal method, not intended to be called by users. */ public void errorOccured(byte clientID, int errorHint, final boolean listenerError, Exception ex) { // scheduler couldn't send packets. invokeErrorOccured(clientID, errorHint, null, ex); disconnect(); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -