Чтение онлайн

ЖАНРЫ

Программирование на Java

Вязовик Н.А.

Шрифт:

Важно подчеркнуть, что после установления соединения с клиентом сервер выходит из метода accept, то есть перестает быть готовым принимать новые запросы. Однако, как правило, желательно, чтобы сервер мог работать с несколькими клиентами одновременно. Для этого необходимо при подключении очередного пользователя создавать новый поток исполнения, который будет обслуживать его, а основной поток снова войдет в метод accept. Приведем пример такого решения:

import java.io.*;

import java.net.*;

public class NetServer {

public static final int PORT = 2500;

private static final int TIME_SEND_SLEEP = 100;

private static final int COUNT_TO_SEND = 10;

private ServerSocket servSocket;

public static void main(String[] args) {

NetServer server = new NetServer;

server.go;

}

public NetServer {

try {

servSocket = new ServerSocket(PORT);

}

catch(IOException e) {

System.err.println("Unable to open Server Socket : " + e.toString);

}

}

public void go {

//

Класс-поток для работы с

//подключившимся клиентом

class Listener implements Runnable {

Socket socket;

public Listener(Socket aSocket) {

socket = aSocket;

}

public void run {

try {

System.out.println("Listener started");

int count = 0;

OutputStream out = socket.getOutputStream;

OutputStreamWriter writer = new

OutputStreamWriter(out);

PrintWriter pWriter = new PrintWriter(writer);

while (count<COUNT_TO_SEND) {

count++;

pWriter.print(((count>1)?",":"")+ "Say" + count);

sleeps(TIME_SEND_SLEEP);

}

pWriter.close;

}

catch(IOException e) {

System.err.println("Exception : " + e.toString);

}

}

}

// Основной поток, циклически выполняющий метод 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)

Массив содержит данные для отправки (созданный пакет будет иметь длину, равную length ), а адрес и порт указывают получателя пакета. После этого вызывается метод send класса DatagramSocket.

try {

DatagramSocket s = new DatagramSocket;

byte data[]= {1, 2, 3};

InetAddress addr = InetAddress.getByName("localhost");

DatagramPacket p =

new DatagramPacket(data, 3, addr, 3456);

s.send(p);

System.out.println("Datagram sent");

s.close;

}

catch (SocketException e) {

e.printStackTrace;

}

catch (UnknownHostException e) {

e.printStackTrace;

}

catch (IOException e) {

e.printStackTrace;

}

Для получения датаграммы также создается экземпляр класса DatagramPacket, но в конструктор передается лишь массив, в который будут записаны полученные данные (также указывается ожидаемая длина пакета). Сокет необходимо создать с указанием порта, иначе, скорее всего, сообщение просто не дойдет до адресата. Используется метод receive класса DatagramSocket (аналогично методу ServerSocket.accept, этот метод также прерывает выполнение потока, пока не придет запрос от клиента). Пример реализации получателя:

Поделиться с друзьями: