Создаем клиент-сервер на сокетах
(С) Алексей Синельников, 2002 год.

Содержание
  • Что такое сокеты?
  • Создаем сервер
  • Создаем клиент
  • Приложения

    Что такое сокеты?
    Для начала давайте определим что такое сервер и клиент. Итак, сервер - это специальная программа, обычно запущенная на отдельном компьютере (хосте, от слова host(eng.) - хозяин), и выполняющая некий круг задач. Клиент, в свою очередь - программа, которая запрашивает сервер выполнить то или иное действие (задачу) и вернуть полученные данные клиенту. На хосте для работы сервера обычно выделяется порт (port). К этому порту и должен будет обращаться клиент. Клиент для связи с портом хоста, который соединен в свою очередь с нужным сервером (программой), создает сокет.
    В целом алгоритм работы системы клиент-сервер выглядит следующим образом:
    1. Сервер подключается к порту на хосте и ждет соединения с клиентом;
    2. Клиент создает сокет и пытается соединить его с портом на хосте;
    3. Если создание сокета прошло успешно, то сервер переходит в режим ожидания команд от клиента;
    4. Клиент формирует команду и передает ее серверу, переходит в режим ожидания ответа;
    5. Сервер принимает команду, выполнеят ее и пересылает ответ клиенту.
    6. и т.д.
    Теперь попробуем создать сервер и клиент.

    Создаем сервер
    Для создания сокетов и управления ими в Java есть специальные классы java.net.Socket и java.net.ServerSocket. Первый для клиента, второй для сервера. Так же нам будут необходимы два класса из пакета java.io.*: BufferedReader и PrintWriter для чтения/записи в сокет (думаю, что читатель уже знаком с этими классами).
    Для начала подключимся к порту хоста. Сделать это можно с помощью конструктора класса ServerSocket. Обратите внимание, что конструктор выбрасывает исключение типа IOException, т.е. нам понадобится блок try - catch:

    
        ServerSocket servers;
        try {
          servers = new ServerSocket(4444);
        } catch (IOException e) {
          System.out.println("Couldn't listen to port 4444");
          System.exit(-1);
        }
    

    После успешного подключения к порту сервер должен ждать подключения от клиента. Сделать это можно так:
    
        Socket fromclient;
        try {
          System.out.print("Waiting for a client...");
          fromclient= servers.accept();
          System.out.println("Client connected");
        } catch (IOException e) {
          System.out.println("Can't accept");
          System.exit(-1);
        }
    

    Рассмотрим этот блок подробнее. Метод servers.accept() позволяет серверу следить за портом, или иначе говоря ждать подключения клиента. Как только клиент подключается - сокет для клиента сразу же создается. В противном случае выбрасывается исключение IOException.
    Как только клиент подключился к серверу, сервер должен создать потоки ввода и вывода для связи с ним. Это можно сделать следующим образом:

    
    	BufferedReader in;
    	PrintWriter    out;
    	in=new BufferedReader(new InputStreamReader(fromclient.getInputStream())); 
    	out = new PrintWriter(fromclient.getOutputStream(),true);
    

    И далее можно просто считывать данные из потока in и записывать данные в out. Исходный код сервера здесь...

    Создаем клиент
    Для создания клиента достаточно класса Socket и двух классов для ввода/вывода (см. Создаем сервер). Также необходимо знать имя компьютера (хоста), на котором запущен сервер и номер порта.
    Конструктор сокета имеет два параметра: имя хоста и номер порта. Опять таки, конструктор выбрасывает исключение типа IOException.
    
          Socket fromserver = null;
          fromserver = new Socket("localhost",4444);
    

    Далее аналогичным образом, как для сервера, создаем потоки ввода вывода. И можно записывать/считывать данные.
    Исходный код клиента здесь....

    Приложения
    Клиент-сервер на примере Echo server (Эхо сервер). Клиент получает обратно строку переданную серверу.
  • Исходный код для клиента
  • Исходный код для сервера

    Несколько замечаний по кодам:
    Обратите внимание на конструкцию методов main :
    
           public static void main(String[] args) throws IOException {}
    
    throws IOException позволит не использовать блоки try-catch для ловки исключения IOException в самом методе, что достаточно удобно.
    В клиентской части используется параметр командной строки для указания имени хоста. Например, если Вы запускаете сервер и клиент на одном компьютере, то клиент надо запускать так:
    
           java client localhost