Шрифт:
Аналогично, класс Socket имеет расширенный конструктор для указания как локального адреса, с которого будет устанавливаться соединение, так и локального порта (иначе операционная система выделяет произвольный свободный порт).
Во-вторых, можно воспользоваться методом setSoTimeout(int timeout) класса ServerSocket, чтобы указать время в миллисекундах, на протяжении которого нужно ожидать подключение клиента. Это позволяет серверу не "зависать", если никто не пытается начать с ним работать. Тайм-аут задается в миллисекундах, нулевое значение означает бесконечное время ожидания.
Важно подчеркнуть, что после установления соединения с клиентом сервер выходит из метода 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);