Вначале мы рассмотрим действия приложения, которое на момент инициализации является сервером.
Первое, что должно сделать серверное приложение, это создать объект класса ServerSocket, указав конструктору этого класса номер используемого порта:
ServerSocket ss; ss = new ServerSocket(9999);
Заметим, что объект класса ServerSocket вовсе не является сокетом. Он предназначен всего лишь для установки канала связи с клиентским приложением, после чего создается сокет класса Socket, пригодный для передачи данных.
Установка канала связи с клиентским приложением выполняется при помощи метода accept, определенного в классе ServerSocket:
Socket s; s = ss.accept();
Метод accept приостанавливает работу вызвавшего потока до тех пор, пока клиентское приложение не установит канал связи с сервером. Если ваше приложение однопоточное, его работа будет блокирована до момента установки канала связи. Избежать полной блокировки приложения можно, если выполнять создание канала передачи данных в отдельном потоке.
Как только канал будет создан, вы можете использовать сокет сервера для образования входного и выходного потока класса InputStream и OutputStream, соответственно:
InputStream is; OutputStream os; is = s.getInputStream(); os = s.getOutputStream();
Эти потоки можно использовать таким же образом, что и потоки, связанные с файлами.
Обратите также внимание на то, что при создании серверного сокета мы не указали адрес IP и тип сокета, ограничившись только номером порта.
Что касается адреса IP, то он, очевидно, равен адресу IP узла, на котором запущено приложение сервера. В классе ServerSocket определен метод getInetAddress, позволяющий определить этот адрес:
public InetAddress getInetAddress();
Тип сокета указывать не нужно, так как для работы с датаграммными сокетами предназначен класс DatagramSocket, который мы рассмотрим позже.