} } // Основной поток, циклически выполняющий метод accept() System.out.println('Server started'); while (true) { try { Socket socket = servSocket.accept(); Listener listener = new Listener(socket); Thread thread = new Thread(listener); thread.start(); } catch(IOException e) { System.err.println('IOException : ' + e.toString()); } } } public void sleeps(long time) { try { Thread.sleep(time); } catch(InterruptedException e) { } } } Пример 16.2.
Теперь объявим клиента. Эта программа будет запускать несколько потоков, каждый из которых независимо подключается к серверу, считывает его ответ и выводит на консоль.
import java.io.*; import java.net.*; public class NetClient implements Runnable { public static final int PORT = 2500; public static final String HOST = 'localhost'; public static final int CLIENTS_COUNT = 5; public static final int READ_BUFFER_SIZE = 10; private String name = null; public static void main(String[] args) { String name = 'name'; for (int i=1; i<=CLIENTS_COUNT; i++) { NetClient client = new NetClient(name+i); Thread thread = new Thread(client); thread.start(); } } public NetClient(String name) { this.name = name; } public void run() { char[] readed = new char[READ_BUFFER_SIZE]; StringBuffer strBuff = new StringBuffer(); try { Socket socket = new Socket(HOST, PORT); InputStream in = socket.getInputStream(); InputStreamReader reader = new InputStreamReader(in); while (true) { int count = reader.read(readed, 0, READ_BUFFER_SIZE); if (count==-1) break; strBuff.append(readed, 0, count); Thread.yield(); } } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } System.out.println('client ' + name + ' read : ' + strBuff.toString()); } } Пример 16.3.
Теперь рассмотрим UDP. Для работы с этим протоколом и на стороне клиента, и на стороне сервера используется класс DatagramSocket. У него есть следующие конструкторы:
DatagramSocket() DatagramSocket(int port) DatagramSocket(int port, InetAddress laddr)
При вызове первого конструктора сокет открывается на произвольном доступном порту, что уместно для клиента. Конструктор с одним параметром, задающим порт, как правило, применяется на серверах, чтобы клиенты знали, на каком порту им нужно пытаться устанавливать соединение. Наконец, последний конструктор необходим для машин, у которых присутствует несколько сетевых интерфейсов.
После открытия сокетов начинается обмен датаграммами. Они представляются экземплярами класса DatagramPacket. При отсылке сообщения применяется следующий конструктор:
DatagramPacket(byte[] buf, int length, InetAddress address, int port)