Шрифт:
public class LHClient implements Runnable {
Ниже приведен список членов класса LHClient.
private LHCanvas canvas;
private DatagramConnection dc;
private boolean connected;Переменные класса должны быть вам знакомы, поскольку они точно такие же, как и в классе LHServer, за исключением отсутствия переменной address. Ниже приведен код конструктора класса LHClient, который выполняет инициализацию некоторых переменных:
public LHClient(LHCanvas c) {
canvas = c;
connected = false;
}Метод start класса LHClient точно такой же, как и аналогичный метод класса LHServer, поэтому давайте перейдем к методу run. В листинге 14.3 приведен код метода run класса LHClient. Листинг 14.3. Метод run класса LHClient отвечает на сообщения, полученные от сервера
public void run {
try {
// соединиться с серверным устройством
canvas.setStatus("Connecting to peer server..."); //Клиент отображает начальное соединение, что говорит о том, что он пытается соединиться с сервером
dc = null;
while (dc == null)
dc = (DatagramConnection)Connector.open("datagram://localhost:5555"); //Номер порта клиента должен совпадать с номером порта сервера
while (true) {
// попытаться отправить сообщение //Если соединение не установлено, отправить клиентское сообщение об установлении соединения серверу
if (!connected)
sendMessage("Client");
// попытаться принять пакет датаграммы
Datagram dg = dc.newDatagram(32);
dc.receive(dg);
// проверить, что датаграмма содержит данные
if (dg.getLength > 0) {
String data = new String(dg.getData, 0, dg.getLength);
if (data.equals("Server")) { //Ответить на сообщение сервера о соединении
// оповестить пользователя об установлении соединения
canvas.setStatus("Connected to peer server.");
connected = true;
}
else {
// отправить данные
canvas.receiveMessage(data); //Сообщение содержит символы азбуки Морзе, поэтому его следует передать холсту
}
}
}
}
catch (ConnectionNotFoundException cnfe) {
System.err.println("The network server is unavailable.");
}
catch (IOException ioe) {
}
}Метод run класса клиента очень похож на аналогичный метод класса сервера за исключением того, что в классе клиента отсутствует переменная адреса при отправлении датаграммы. Кроме того, URL немного отличается от того, который использовался в классе сервера. И снова важно отметить, что номер порта (5555) должен быть одинаковым для клиента и сервера.
Класс LHClient также реализует метод sendMessage, который также очень похож на аналогичный метод сервера. В листинге 14.4 приведен код метода sendMessage клиента.
Листинг 14.4. Метод sendMessage класса LHClient отправляет строковое сообщение серверу как пакет датаграммыpublic void sendMessage(String message) {
// отправить сообщение
try {
// преобразовать строку в массив байтов
byte[] bytes = message.getBytes;
// отправить сообщение
Datagram dg = null; //Упаковка данных в датаграмму и отправка клиенту
dg = dc.newDatagram(bytes, bytes.length);
dc.send(dg);
}
catch (Exception e) {
}
}Единственное отличие методов sendMessage сервера и клиента – это то, что версия класса клиента не использует адреса при отправлении пакета серверу. Это незначительное, но очень важное отличие. Холст мидлета Lighthouse Когда классы сервера и клиента созданы, перейдем к созданию холста класса Lighthouse. Класс называется LHCanvas, он выводит на экран информацию о ходе подключения, а также отображает нужную картинку с маяком в соответствии с получаемой информацией.
private Display display;
private boolean sleeping;
private long frameDelay;
private Image[] background = new Image[2]; //Эта переменная говорит о том, является данное приложение образом сервера или клиента
private LHClient client;
private LHServer server;
private boolean isServer;
private String status = "";
private int mode; // 0 = none, 1 = dot, 2 = dash
private int morseTimer;Переменная background содержит два изображения маяка: с включенным и погашенным огнем. Переменные server и client – это объекты сервера и клиента соответственно, они отвечают за работу мидлета с сетью. Переменная isServer очень важна, она определяет сетевой режим работы мидлета. Эта переменная определяет, как работает мидлет – как клиент или как сервер.
Текст статуса хранится в переменной status. временная mode используется для контроля вывода изображений маяка, а также интервалов времени. Помните, что точка в азбуке Морзе по длительности в три раза меньше тире, поэтому в мидлете Lighthouse используется таймер вывода изображения маяка, который задерживает изображение с включенным огнем в соответствии с отображаемым сигналом. За задержку отвечают переменные mode и morseTimer.
Переменные холста широко используются в методе start, код которого приведен в листинге 14.5.
Листинг 14.5. Метод start класса LHCanvas запускает сервис Клиент-Серверpublic void start {
// установить экран как холст
display.setCurrent(this);
// инициализация фонового изображения
try {
background[0] = Image.createImage("/LighthouseOff.png");
background[1] = Image.createImage("/LighthouseOn.png");
}
catch (IOException e) {
System.err.println("Failed loading images!");
}
// инициализация режима и таймера
mode = 0;
morseTimer = 0;
// запуск сетевого сервиса
if (isServer) { //Начиная с этой точки, мидлет работает в режиме сервера или клиента
server = new LHServer(this);
server.start;
}
else {
client = new LHClient(this);
client.start;
}
// начало потока анимации
sleeping = false;
Thread t = new Thread(this);
t.start;
}После того как фоновые изображения инициализированы, метод start инициализирует таймер и режим. Переменная mode инициализируется 0, что соответствует погашенному огню маяка (нет сообщения), в то время как переменная morseTimer обнуляется, несмотря на то что она не используется в отсутствие сообщения.
Наиболее важная часть кода метода start реализует режим сервера или клиента. В зависимости от значения переменной isServer создается экземпляр класса LHServer или LHClient. После этого создается сетевой объект, вызывается метод старт, запускающий поток соединения.
Метод start инициализирует мидлет Lighthouse, а метод update обрабатывает пользовательский ввод и позволяет вам отправлять сообщения, закодированные азбукой Морзе. В листинге 14.6 приведен код метода update.
Листинг 14.6. Метод update класса LHCanvas отправляет сообщения, закодированные азбукой Морзе, в соответствии с нажатыми клавишамиprivate void update {
// обработка пользовательского ввода
int keyState = getKeyStates;
if ((keyState & LEFT_PRESSED) != 0) {
if (isServer) //Передать точку на другой телефон
server.sendMessage("Dot");
else
client.sendMessage("Dot");
status = "Dot";
}
else if ((keyState & RIGHT_PRESSED) != 0) {
if (isServer) //Передать тире на другой телефон
server.sendMessage("Dash");
else
client.sendMessage("Dash");
status = "Dash";
}
// обновить таймер кода Морзе
if (mode != 0) {
morseTimer++;
// тайм-аут точки
if (mode == 1 && morseTimer > 3)
mode = 0;
// тайм-аут тире
else if (mode == 2 && morseTimer > 9)
mode = 0;
}
}Метод update проверяет нажатие клавиш и в соответствии с нажатыми клавишами отправляет нужный знак. Клавиша влево соответствует точке, а клавиша вправо – тире. Чтобы отправить код азбуки Морзе, метод update просто вызывает метод sendMessage сетевого объекта (клиента или сервера).
После проверки нажатий клавиш и отправки сообщения, если необходимо, метод update обновляет таймер Морзе. Если значение переменной mode равно 1, то выводится точка, затем значение таймера увеличивается до 3, после чего выводится изображение маяка с погашенным огнем. Если значение переменной mode равно 2, выводится тире, при этом счетчик будет увеличиваться до 9. И наконец, если значение переменной mode равно 0, то следует вывести изображение маяка с погашенным огнем, таймер не изменяется.
Метод draw выводит изображение маяка на экран (листинг 14.7).
Листинг 14.7. Метод draw класса LHCanvas выводит на экран нужное изображение маякаprivate void draw(Graphics g) {
// вывести фоновое изображение
if (mode == 0) //В зависимости от режима маяк светится или нет
g.drawImage(background[0], 0, 0, Graphics.TOP | Graphics.LEFT);
else
g.drawImage(background[1], 0, 0, Graphics.TOP | Graphics.LEFT);
// вывести сообщение о статусе
g.setColor(255, 255, 255); // white
g.setFont(Font.getFont(Font.FACE_SYSTEM,Font.STYLE_BOLD, Font.SIZE_MEDIUM));
g.drawString(status, getWidth / 2, 5, Graphics.TOP | Graphics.HCENTER); // В верхней части экрана выводится статусное сообщение
// вывести содержимое буфера на экран
flushGraphics;
}Метод draw начинается с проверки значения переменной mode, которая определяет, какое изображение маяка следует вывести. Если значение этой переменной равно 0, то выводится изображение маяка с погашенным огнем, в противном случае выводится изображение маяка с включенным огнем. Остальной код выводит в нижней части экрана сообщение о статусе соединения. Сообщение о текущем статусе выводится функцией setStatus:
public void setStatus(String s) {
// установить текущий статус
status = s;
}