Прохожу курс "Построение распределенных систем на Java" в третьей лекции где описывается TCPServer вылетает эта ошибка
"Connection cannot be resolved to a type" Java version 1.7.0_05 |
Пример использования API java.net
Второй пример
Рассмотренный в предыдущем примере способ взаимодействия имеет очень существенный недостаток, который происходит от выбранного нами протокола взаимодействия между клиентом и сервером (что еще раз подчеркивает важность правильного выбора протокола). Этот недостаток состоит в том, что наш протокол полностью не защищен от ошибок приложения. Предположим, например, что наш клиент при передаче операции заведения новой карты вместо того, чтобы передать три параметра (код операции, имя клиента и номер карты), случайно передал четыре - код операции, имя клиента, фамилия клиента и номер карты (такое возможно в случае ошибки программиста, реализующего приложение-клиент, или в случае появления новой, расширенной версии приложения). Поскольку сервер ничего об этом не знает, он считает из потока три параметра, а четвертый (номер карты) будет интерпретирован как код следующей операции. Таким образом, использование явной передачи параметров методов может приводить к трудноуловимым ошибкам.
Попробуем модифицировать наше приложение, чтобы избавиться от этого недостатка. Идея состоит в том, чтобы группировать передаваемые данные некоторым образом так, чтобы даже в случае изменения их структуры не происходило их перемешивания.
Мы могли бы модифицировать протокол из предыдущего примера, введя в него разделители команд или предусмотрев первоначальный обмен клиента и сервера метаданными, описывающими передаваемые объекты - существует масса способов достичь желаемого результата. Однако, поскольку приложение написано на языке Java, разумно воспользоваться средствами, уже встроенными в эту платформу. Речь идет о сериализации объектов.
В самом деле, рассмотрим еще раз нашу задачу. Все, что необходимо, - реализовать механизм обмена структурами данных (или объектами) между клиентом и сервером. И встроенный механизм сериализации в этом случае нам идеально подходит. Мы будем передавать по сети не отдельные "поля", а целые объекты.
Первое, что необходимо сделать, - выделить эти "транспортные" объекты. В нашем случае таких объектов будет два - объект "карта" и объект "операция над картой". Поскольку в нашем примере рассматривается система, выполняющая очень небольшое число действий, все операции системы можно свести к двум типам - операции, в которых аргументом является карта целиком, и операции, в которых в качестве аргумента выступает начисление/списание средств с карты. К первому типу относятся операции заведения новой карты и операция получения баланса карты (баланс мы будем считать ее атрибутом), ко второму - операции пополнения баланса и расчета.
Класс CardOperation
Первый класс, который мы реализуем, - класс "операция над картой" (пример 4.4).
1 package com.asw.net.ex2; 2 import java.util.*; 3 import java.io.*; 4 5 6 public class CardOperation implements Serializable { 7 public CardOperation(String card,double amount,Date operationDate){ 8 this.card = card; 9 this.amount = amount; 10 this.operationDate = operationDate; 11 } 12 public String card; 13 public double amount; 14 public Date operationDate; 15 }Листинг 4.4. Транспортный класс CardOperation
Первое, что стоит отметить: класс CardOperation объявлен реализующим интерфейс Serializable.Этот интерфейс является "тэгирующим" - он не содержит полей или методов и служит только для того, чтобы сообщить о том, что данный класс сериализуем.
Класс содержит три поля, которые и составляют его полезное наполнение - номер карты, сумма начисляемых/списываемых средств и дата операции.
Класс Card
Второй транспортный класс представляет собой представление карты и выглядит следующим образом (пример 4.5).
1 package com.asw.net.ex2; 2 import java.io.Serializable; 3 import java.util.*; 4 5 public class Card implements Serializable{ 6 public Card(String person, Date createDate, String cardNumber,double balance){ 7 this.person = person; 8 this.createDate = createDate; 9 this.cardNumber = cardNumber; 10 this.balance = balance; 11 } 12 public String person; 13 public transient Date createDate; 14 public String cardNumber; 15 public double balance; 16 public String toString(){ 17 return "Card: cardNumber="+cardNumber+"\tBalance="+balance+"\tPerson="+person+"\tCreateDate="+createDate+""; 18 } 19 }Листинг 4.5. Транспортный класс Card
Поскольку его тоже предстоит передавать по сети, он также объявлен как сериализуемый и содержит следующие поля: ФИО клиента, дату заведения карты, номер карты и текущий баланс. Для удобства вывода на экран перекрыт метод toString(), который распечатывает значения всех полей класса.
Перейдем теперь к серверным классам.
Класс BillingService
Первый из серверных классов - BillingService (пример 4.6).
1 package com.asw.net.ex2; 2 import java.net.*; 3 import java.util.Hashtable; 4 import java.io.*; 5 6 public class BillingService extends Thread{ 7 private int serverPort = 7896; 8 private ServerSocket ss; 9 private Hashtable hash; 10 11 public static void main(String[] args) { 12 BillingService bs = new BillingService(); 13 bs.start(); 14 } 15 16 public BillingService(){ 17 hash = new Hashtable(); 18 } 19 20 public void run(){ 21 try { 22 ss = new ServerSocket(serverPort); 23 System.out.println("Server started"); 24 while(true){ 25 System.out.println("new client waiting..."); 26 Socket s = ss.accept(); 27 System.out.println("Client accepted"); 28 BillingClientService bcs = new BillingClientService(this,s); 29 System.out.println("bcs created"); 30 bcs.start(); 31 } 32 } catch (IOException e) { 33 e.printStackTrace(); 34 } 35 36 } 37 38 public void addNewCard(Card card) { 39 hash.put(card.cardNumber, card); 40 } 41 public void addMoney(String card, double money) { 42 Card c = (Card)hash.get(card); 43 if (c==null) { 44 System.out.println("Bad Card number\n"); 45 return; 46 }; 47 c.balance+=money; 48 hash.put(card,c); 49 } 50 public Card getCard(String card){ 51 return (Card)hash.get(card); 52 } 53 }Листинг 4.6. Серверный класс BillingService
Несложно заметить, что он очень похож на BillingService из предыдущего примера. И действительно, он точно так же хранит хэш-таблицу карт, имеет методы для обработки соответствующих событий - добавления новой карты, запроса баланса карты и обработки операций изменения баланса. Основной цикл run (строки 21-32) тоже точно такой же - сначала создается серверный сокет, затем ожидаются соединения клиентов. При появлении нового клиента создается экземпляр класса BillingClientService (строка 28), который и занимается всем дальнейшим обслуживанием клиента.
Однако есть и отличие - теперь в качестве элемента хранения в хэш-таблице используются экземпляры класса Card (ключом по-прежнему выступает ее номер), а метод getCard,заменивший метод getCardBalance,возвращает не скалярное значение, а экземпляр класса Card.