📄 server.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.ByteArrayOutputStream;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.IOException;import java.util.Enumeration;import java.util.Hashtable;import java.util.Vector;import javax.bluetooth.BluetoothStateException;import javax.bluetooth.DiscoveryAgent;import javax.bluetooth.L2CAPConnection;import javax.bluetooth.L2CAPConnectionNotifier;import javax.bluetooth.UUID;import javax.microedition.io.Connector;import net.sf.btw.tools.Logger;/** * Provides functionality of a server. Intended usage: * <ul> * <li>Create the server object instance</li> * <li>Register a {@link #listener} for server events</li> * <li>Call {@link #startServer()}</li> * <li>You can use sendBuffer methods to send messages to clients</li> * <li>Destroy the server using {@link #stopServer()}</li> * </ul> * * @author Martin Vysny */public final class Server extends Peer implements IErrorListener { /** * ID of a server. May be used for testing purposes but games should use * their own generated UID. The <code>uuidgen -t</code> command will * generate new UUID. Just remove the hyphens '<code>-</code>' and * create new {@link UUID} object. */ public final static UUID SERVER_UUID = new UUID( "EFE7C3AAAB2C11DBA0EB0016D45FB918", false); //$NON-NLS-1$ /** * Starts acting as a client. * * @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 uuid * Server UUID. Each game should have its own id. * @param listener * Listens for server events. Must not be <code>null</code> */ public Server(final int receiveMTU, final int transmitMTU, final UUID uuid, final IServerListener listener) { super(uuid, receiveMTU, transmitMTU, listener); listenerURL = "btl2cap://localhost:" //$NON-NLS-1$ + uuid.toString() + ";authenticate=false;authorize=false;encrypt=false;ReceiveMTU=" //$NON-NLS-1$ + receiveMTU + ";TransmitMTU=" + transmitMTU; //$NON-NLS-1$ Logger.info("Listening on " + listenerURL, null); //$NON-NLS-1$ } /** * Listener URL fed to the {@link Connector#open(String)} method. */ protected final String listenerURL; /** * A map of connected clients. Map byte ID into the * {@link Listener listeners} that connects to the client. */ protected final Hashtable connectedClients = new Hashtable(Peer.MAX_CLIENTS); /** * Listener that waits for a connection and is not yet present in the * {@link #connectedClients} map. */ protected volatile Listener waitingForConnectionListener; /** * Starts the server and opens listener ports. The function leaves * immediately. * * @throws BluetoothStateException * if bluetooth error occurs. */ public void startServer() throws BluetoothStateException { synchronized (connectedClients) { checkNotRunning(); getDevice().setDiscoverable(DiscoveryAgent.GIAC); waitingForConnectionListener = new Listener(); waitingForConnectionListener.start(); scheduler = new PacketScheduler(this); } } /** * Checks if the server is currently running. * * @return <code>true</code> if */ public boolean isRunning() { synchronized (connectedClients) { return scheduler != null; } } /** * Asserts that the server is not running. */ private void checkNotRunning() { if (isRunning()) throw new IllegalStateException("Server is running"); //$NON-NLS-1$ } /** * Asserts that the server is running. */ private void checkRunning() { if (!isRunning()) throw new IllegalStateException("Server is not running"); //$NON-NLS-1$ } /** * Packet scheduler instance. If <code>null</code> then the server is * stopped. */ protected PacketScheduler scheduler; /** * Closes all connections and shutdowns server. The function blocks until * the server is stopped completely. Does nothing if the server is not * running. */ public void stopServer() { synchronized (connectedClients) { if (!isRunning()) return; if (waitingForConnectionListener != null) { waitingForConnectionListener.close(); waitingForConnectionListener = null; } // close all connections. We need to clone the client hashtable // because the listener removes itself from the table when closed. final Vector listeners = new Vector(); for (final Enumeration e = connectedClients.elements(); e .hasMoreElements();) { listeners.addElement(e.nextElement()); } for (final Enumeration e = listeners.elements(); e .hasMoreElements();) { final Listener l = (Listener) e.nextElement(); l.close(); } connectedClients.clear(); scheduler.stop(); scheduler = null; } } /** * Returns ID not used yet by any client. * * @return unoccupied ID. */ byte getFreeClientId() { synchronized (connectedClients) { for (byte i = 1; i < Peer.MAX_CLIENTS; i++) { if (!connectedClients.containsKey(Peer.getID(i))) return i; } throw new IllegalStateException("All ids are occupied"); //$NON-NLS-1$ } } /** * Returns set of connected clients. * * @return hashtable of {@link Byte} client IDs. Values are client names ({@link String} * instances). */ public Hashtable getClientIDs() { synchronized (connectedClients) { final Hashtable result = new Hashtable(connectedClients.size()); for (final Enumeration e = connectedClients.keys(); e .hasMoreElements();) { final Byte id = (Byte) e.nextElement(); final Listener listener = (Listener) connectedClients.get(id); String devName = listener.deviceName; if (devName == null) { devName = ""; //$NON-NLS-1$ } result.put(id, devName); } return result; } } /** * Sends the buffer to the client. The buffer is scheduled for sending and * will be sent ASAP. Function does not block. * * @param clientID * the client ID * @param buffer * the buffer to be sent. It must not be modified until the * packet has been sent. */ public void sendBuffer( final byte clientID, final byte[] buffer) { if (buffer == null) throw new IllegalArgumentException("Null buffer"); //$NON-NLS-1$ synchronized (connectedClients) { checkRunning(); final Listener l = (Listener) connectedClients.get(Peer .getID(clientID)); if (l == null) return; scheduler.sendPacket(Peer.getID(clientID), buffer); } } /** * Sends the buffer to the client. The buffer is scheduled for sending and * will be sent ASAP. Function does not block. * * @param clientIDs * broadcasts the message to these clients. List of {@link Byte} * instances. * @param exceptClientId * If this client ID is present in given enumeration then it is * skipped. Use <code>-1</code> if you don't want to skip any * client. * @param buffer * the buffer to be sent. It must not be modified until the * packet has been sent. */ public void sendBuffer(final Enumeration clientIDs, final byte exceptClientId, final byte[] buffer) { if (buffer == null) throw new IllegalArgumentException("Null buffer"); //$NON-NLS-1$ synchronized (connectedClients) { checkRunning(); for (; clientIDs.hasMoreElements();) { final Byte clientID = (Byte) clientIDs.nextElement(); if (clientID.byteValue() == exceptClientId) continue; final Listener l = (Listener) connectedClients.get(clientID); if (l == null) continue; scheduler.sendPacket(clientID, buffer); } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -