Как создать программу клиент сервер

Наиболее распространённый способ создания распределённого приложения с клиент-серверной архитектурой – это использование сокетов.

1 Понятие сокета

  • Стили соединения гарантируют доставку всех пакетов в том порядке, в каком они были отправлены. Если во время передачи пакеты были потеряны или доставлены в неправильном порядке, получатель автоматически отправляет запрос на их повторную передачу. Стиль соединения напоминает телефонный звонок: адреса отправителя и получателя фиксируются в начале соединения, при установке подключения.
  • Стили дейтаграмм не гарантирует доставки и правильного порядка прибытия. Пакеты могут быть потеряны или переупорядочены в пути из-за сетевых ошибок. Каждый пакет должен быть помечен его адресатом, и нет гарантии, что он будет доставлен. Система гарантирует только «максимальные усилия», поэтому пакеты могут исчезнуть или прибыть в различном порядке. Сокет стиля дейтаграммы ведет себя сходно с почтой. Отправитель определяет адрес получателя для каждого индивидуального сообщения.

Пространство имен определяет, как записаны адреса сокета (socket addresses). Адрес сокета идентифицирует один конец подключения сокета. Например, адреса сокета в локальном пространстве имен являются обычными именами файлов. В пространстве имен Интернет-адрес сокета состоит из IP-адреса главного компьютера, присоединенного к сети, и номера порта, который идентифицирует сокет среди множества сокетов на том же главном компьютере (порты с 1 по 1024 зарезервированы операционной системой).

КЛИЕНТ-СЕРВЕРНОЕ ПРИЛОЖЕНИЕ НА PYTHON | ЧАСТЬ 1 | СВЯЗЬ КЛИЕНТА И СЕРВЕРА

Протокол определяет, как передаются данные. Существуют следующие виды протоколов: TCP/IP, первичные сетевые протоколы, используемые Интернетом; сетевой протокол AppleTalk; локальный UNIX протокол взаимодействия. Не все комбинации стилей, пространств имен и протоколов поддерживаются.

Для организации обмена информацией по протоколу TCP обязательно требуется открыть соединение между конечными точками (характеризующимися IP-адресом и портом). При этом будут использоваться клиентские (их может быть несколько) и серверные (обычно он существует в единственном экземпляре) сокеты. Клиентские сокеты (на стороне клиента) пытаются открыть соединение с удаленной конечной точкой (на стороне сервера), а серверный сокет (на стороне сервера) ожидает или «слушает» входящие соединения. В общих чертах последовательность действий описывается следующим образом:

на стороне клиента:

  • создание клиентского сокета;
  • установка параметров сокета (IP-адрес и порт, к которым необходимо подключиться);
  • установка соединения между сокетом и удаленной конечной точкой;
  • отправка/получение информации;
  • разрыв соединения и освобождение сокета.

на стороне сервера:

  • создание серверного сокета;
  • установка параметров серверного сокета (IP-адрес и порт, на которые ожидаются подключения);
  • перевод серверного сокета в режим отслеживания входящих соединений;
  • при наличии входящего соединения: получить отдельный сокет для работы с этим конкретным соединением;
  • отправка/получение информации;
  • по окончании работы с клиентом: разрыв соединения и освобождение сокета, привязанного к этому клиенту;
  • по окончании работы сервера: освобождение серверного сокета.

2 Реализация сокетов на языке Java

Для создания соединения можно использовать API (Application Programming Interface), входящий в состав пакета java.net. Этот пакет предоставляет возможность для реализации сетевого взаимодействия с применением одного из двух транспортных протоколов: UDP и TCP.

Socket или как создать собственный сервер на Python в домашних условиях #1 | Базовый курс Python

2.1 Стек протоколов TCP/IP

Архитектура протоколов TCP/IP, известная как стек протоколов TCP/IP, возникла в результате исследований в области протоколов и разработок, выполнявшейся в экспериментальной сети с коммутацией пакетов под названием ARPANET, которая была основана Управлением перспективных исследовательских программ Министерства обороны США (DARPA).

В общем можно сказать, что в обмене информацией всегда принимают участие три агента: приложения, узлы (компьютеры) и сети. К приложениям относятся программы, предназначенные, например, для передачи файлов или электронной почты. Приложения, о которых идет речь, являются распределенными приложениями, включающими в себя обмен данными между двумя и более компьютерными системами. Компьютеры соединены между собой в сети, и предназначенные для обмена данные передаются по сети от одного компьютера к другому. Таким образом, передача данных от одного приложения другому (или от одного компонента другому в рамках одного распределенного приложения) включает в себя, во-первых, получение данных тем узлом, на котором находится приложение-адресат, и, во-вторых, получение данных именно тем выполняющимся на узле-адресате приложением, которому они предназначены (одновременно на узле могут выполняться несколько приложений).

Ввиду этого в задаче обмена информацией выделяют пять основных относительно независимых уровней:

  • физический уровень;
  • уровень доступа к сети (сетевой);
  • межсетевой уровень;
  • транспортный уровень;
  • уровень приложений.

На физическом уровне находится физический интерфейс между устройством передачи данных и передающей средой. На этом уровне задаются характеристики передающей среды, природа сигналов, скорость передачи данных и т.д.

Уровень доступа к сети связан с обменом данными между конечной системой (рабочей станцией, сервером и т.д.) и сетью, к которой подсоединена эта система. Узел-отправитель должен передать в сеть адрес узла-адресата, чтобы сеть могла направить данные по месту требования.

Уровень доступа к сети рассматривается в связи с доступом к сети и маршрутизацией данных между двумя подключенными к сети оконечными системами. В тех случаях, когда устройства подключены к разным сетям, нужны дополнительные процедуры, позволяющие данным переходить из одной сети в другую. Такие функции относятся к межсетевому уровню. На этом уровне функции межсетевой маршрутизации предоставляются с помощью Интернет-протокола (Internet Protocol — IP). Интернет-протокол может быть реализован не только в конечных системах, но и в маршрутизаторах.

Независимо от природы приложений обмен данными должен быть надежным, т.е. хотелось бы иметь уверенность в том, что все данные попали к приложению-адресату и что эти данные получены в том порядке, в котором они были отправлены. Механизмы обеспечения надежности, по сути, независимы от природы приложений, таким образом, имеет смысл выделить такие механизмы в один общий уровень, совместно используемый всеми приложениями. Этот уровень называется транспортным. Чаще всего для него применяется протокол управления передачей (Transmission Control Protocol — TCP).

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

Итак, чтобы обмен информацией был возможен, каждый элемент системы должен иметь уникальный адрес. Фактически, нужно указать два уровня адресации. Каждый узел сети должен обладать своим уникальным глобальным сетевым адресом, это позволит доставить данные соответствующему узлу. Каждый процесс (компонент) на узле должен иметь адрес, который был бы уникальным в пределах этого узла, что даст возможность транспортному протоколу (TCP) доставить данные нужному процессу. Этот адрес в терминологии протоколов семейства TCP/IP называют портом.

Для большинства приложений, выполняющихся в рамках архитектуры протокола TCP/IP, протоколом транспортного уровня выступает TCP. Этот протокол обеспечивает надежное соединение для передачи данных от одного приложения к другому.

Кроме него существует еще один широко используемый протокол транспортного уровня, входящий в набор протоколов TCP/IP: пользовательский протокол дейтаграмм (User Datagram Protocol — UDP). Протокол UDP предоставляет сервис без установления соединения, предназначенный для процедур на уровне приложения; он не гарантирует доставку, сохранение последовательности при приеме переданных пакетов или защиту от их дублирования. Он позволяет процессу отправлять сообщения другим процессам, с помощью минимального протокольного механизма. Протокол UDP выполняет крайне ограниченный набор функций, так как работает без установления соединения, он только добавляет к протоколу IP некоторые возможности адресации портов.

2.2 Состав пакета java.net

2.2.1 Средства передачи по протоколу UDP

Для работы с UDP в пакете java.net определены следующие классы.

1. DatagramSocket — предназначен для посылки/приема UDP дейтаграмм.

  • DatagramSocket() — создаваемый сокет присоединяется к любому свободному порту на локальной машине;
  • DatagramSocket (int port) — создаваемый сокет присоединяется к порту port на локальной машине;
  • DatagramSocket(int port, InetAddress addr) — создаваемый сокет присоединяется к порту port ; аргумент addr – IP-адрес сервера.
  • send(DatagramPacket pack) — отправляет дейтаграмму, упакованную в пакет pack ;
  • receive(DatagramPacket pack) — дожидается получения дейтаграммы и заносит ее в пакет pack ;
  • setSoTimeout() — устанавливает тайм-аут для операций сокета;
  • close() — закрывает сокет.
Читайте также:
Какие есть программы помощи многодетным семьям

2. DatagramPacket — предназначен для представления единичной дейтаграммы.

  • DatagramPacket(byte[] buf, int length) — служит для получения пакета длиной length , buf — буфер для получения дейтаграммы;
  • DatagramPacket(byte[] buf, int length, InetAddress addr, int port) — Создает пакет дейтаграммы длиной length , чтобы отправить его к указанному номеру порта ( port ) на указанном узле ( address ), buf — буфер, содержащий данные для передачи.

Кроме того пакет содержит вспомогательные методы:

  • connect(InetAddress addr, int port) — установить соединение;
  • disconnect() — разъединить;
  • InetAddress.getByName(host) — получить IP-адрес хоста;
2.2.2 Примеры UDP-соединения

Ниже приведены java-классы, реализующие клиентскую и серверную части архитектуры, которые используют рассмотренные выше механизмы для организации взаимодействия.

Пример UDP клиента:

Приведённая в примере программа создает сокет, соединяется с сервером (порт 2100), пересылает ему сообщение и ждет ответа:

import java.net.*; import java.io.*; public class UDPClient < public static void main(String args[])< try < // создаём сокет DatagramSocket aSocket = new DatagramSocket(); // задаём строку для передачи String str = «Hello»; // и преобразуем её в поток байт byte [] message = str.getBytes(); // получаем IP-адрес компьютера в формате Java InetAddress aHost = InetAddress.getByName(«localhost»); // задаём порт int sPort = 2100; // создаём дейтаграмму, длина которой определяется длиной // сообщения DatagramPacket request = new DatagramPacket(message, message.length, aHost, sPort); // передаём серверу aSocket.send(request); // определяем буфер под ответ сервера byte [] buffer = new byte[1000]; // создаём дейтаграмму под ответ сервера DatagramPacket reply = new DatagramPacket(buffer, buffer.length); // принимаем ответ aSocket.receive(reply); // выводим ответ на консоль System.out.println(«Reply: » + new String(reply.getData())); // закрываем сокет aSocket.close(); >catch (SocketException e) < // если не получилось создать сокет System.out.println(«Socket: » + e.getMessage()); >catch (IOException e) < // ошибка при приеме System.out.println(«IO: » + e.getMessage()); >> >

В первых строках кода происходит импорт необходимых библиотек (пакетов) классов — в нашем случае это java.net и java.io . Первый пакет содержит необходимые нам классы для работы с UDP, второй определяет необходимые классы ввода/вывода.

Класс называется UDPClient , он содержит единственный статический метод main() , являющийся точкой входа в программу. В нём создаётся сокет и пакет с текстовым сообщением, который затем будет передан серверу. После передачи происходит ожидание ответа от сервера, полученный ответ выводится на экран.

Адрес получателя определяется в пакете, а не в сокете, через который он передаётся. Поэтому один и тот же сокет может быть использован для передачи пакетов разным узлам, и этот же сокет может применяться для приема пакета от сервера. После использования сокет должен быть закрыт ( aSocket.close() ).

Пример UDP сервера:

Метод main() класса UDPServer создает сокет, принимает запрос клиента и возвращает клиенту полученное от него текстовое сообщение:

import java.net.*; import java.io.*; public class UDPServer < public static void main(String args[]) < DatagramSocket aSocket = null; try< // создаём сокет: порт 2100 aSocket = new DatagramSocket(2100); // резервируем буфер под клиентское сообщение byte [] buffer = new byte[1000]; while(true)< // бесконечный цикл // резервируем дейтаграмму под пакет клиента DatagramPacket request = new DatagramPacket(buffer, buffer.length); // принимаем пакет клиента aSocket.receive(request); // создаём ответную дейтаграмму DatagramPacket reply = new DatagramPacket(request.getData(), request.getLength(), request.getAddress(), request.getPort()); // отправляем ответ клиенту aSocket.send(reply); >> catch (SocketException e) < // обрабатываем ошибку создания сокета System.out.println(«Socket: » + e.getMessage()); >catch (IOException e) < // обрабатываем ошибку передачи пакета System.out.println(«IO: » + e.getMessage()); >finally < // закрываем сокет if(aSocket != null) aSocket.close(); >> >

После запуска сервер переходит в режим ожидания сообщений от клиента. Поскольку нами не предусмотрено никакого механизма останова сервера, выгрузить его может либо произошедшая ошибка, либо насильственное прерывание процесса.

После запуска клиент отправляет строку на сервер, печатает ее в консоли и завершает работу. Сервер же продолжает ожидать очередное подключение следующего клиента.

Сначала производится запуск сервера, а затем клиента.

2.2.3 Средства передачи по протоколу TCP

Классы:
1. Socket

Конструктор: Socket(InetAddress host, int serverPort) – создаёт клиентский сокет, аргументы IP-адрес сервера и порт;

2. ServerSocket
Конструктор: ServerSocket(int serverPort) – служит для создания «слушающего» сокета на сервере.

Метод: accept() – ожидание сервером нового соединения.

Пример (на стороне сервера):

ServerSocket servsock = new ServerSocket(7896); Socket sock = servsock.accept();

Первая строка примера создаёт «слушающий» сокет сервера (ожидающий клиента). Во второй строке метод accept() серверного сокета ( servsock ) возвращает соответствующий сокет ( sock ) для общения с клиентом.

После сеанса связи сокеты следует закрыть, используя метод close() .

Источник: pro-prof.com

Разработка клиент-серверного чата на Java. Часть 1. Немного теории и сервер

Разработка клиент-серверного чата на Java. Часть 1. Немного теории и сервер

2012-06-23 в 20:53, admin , рубрики: java, клиент-серверные приложения, ооп, Софт, чат, метки: java, клиент-серверные приложения, чат

Краткое описание

На данный момент заканчиваю 2-й курс универститета, одной из лабораторных работ по курсу Java было написание чата. После того, как разобрался в теме сокетов, сериализации объектов и MVC, хотелось бы поделиться с читателим, тем более, что оно мне несказанно помогло при написании проекта.

Ну и, разумеется, учту все ошибки и недочеты, которые будут озвучены.

Немного теории

Итак, для начала. Проект будет состоять из двух частей: клиента и сервера. Клиент будет иметь GUI, написанный с помощью библиотеки Swing. Сервер GUI иметь не будет, только log-файл и небольшой вывод в консоль.

Для написания чата, нам понадобятся некоторые знания.

Сокеты

Поскольку взаимосвязь клиента и сервера у нас будет реализована с помощью сокетов, познакомимся с ними поближе.

Сокеты (Википедия)

Со́кеты (англ. socket — углубление, гнездо, разъём) — название программного интерфейса для обеспечения обмена данными между процессами. Сокет — абстрактный объект, представляющий конечную точку соединения.

Каждый процесс может создать слушающий сокет (серверный сокет) и привязать его к какому-нибудь порту операционной системы. Слушающий процесс обычно находится в цикле ожидания, то есть просыпается при появлении нового соединения.

Для нас это означает, что сервер будет слушать какой-либо порт (для большей универсальности, мы будем задавать порт в конфигурационном файле) и после подключения клиента, будем производить с ним какие-то действия.

Пример кода

ServerSocket socketListener = new ServerSocket(«1234»); //Слушаем порт 1234 while (true) < Socket client = null; while (client == null) < client = socketListener.accept(); //Пытаемся соединиться с клиентом >//Как только подключились, можем как-то с ним взаимодействовать >

Передача объектов по сети

Но просто получать сообщение от клиента нам мало. Нам хочется знать его имя, IP-адрес, а также передавать ему в ответ список подключенных пользователей. Таким образом, просто передача текстовых данных нас не устроит. У нас есть 2 выхода:
1. Передавать xml-строку с описанием всей информации
2. Передавать сериализованный объект, в котором будут храниться все необходимые нам данные в виде полей.

Не будем говорить о плюсах и минусах каждого подхода. Воспользуемся вторым вариантом. (А если понадобится, когда-нибудь потом, я напишу второй)

Итак, что такое сериализация объектов.

Сериализация (Википедия

Сериализация — процесс перевода какой-либо структуры данных в последовательность битов. Обратной к операции сериализации является операция десериализации — восстановление начального состояния структуры данных из битовой последовательности.

Сериализация используется для передачи объектов по сети и для сохранения их в файлы.

В Java единственное, что нужно для сериализации объекта — имплементировать интерфейс Serializable, который является интерфейсом-маркером, т.е не содержит методов.

Пишем Сервер

Итак, краткое описание работы сервера.

Сервер работает в вечном цикле. Как только подключается новый клиент, он создает для работы с ним новый поток, оповещает уже подключенных клиентов о новом пользователей, а новичку отсылает какое-то количество последних сообщений в чате. Клиент же, при подключении сообщает о себе некоторую информациию, а также какое-то сообщение, идентифицирующее то, что он только что подключился.

Но помимо этого, надо не забыть о том, что клиенты могут и отключаться. То есть мы периодически должны обмениваться с клиентами сигналами (ping’овать друг друга), чтобы в случае отключения клиента (или сервера) все об этом узнали.

Итак, приступим. Создадим наш первый класс

Server.java

package anexroid.server; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; public class Server < public static void main(String[] args) < try < //Создаем слушатель ServerSocket socketListener = new ServerSocket(«1234»); while (true) < Socket client = null; while (client == null) < client = socketListener.accept(); >new ClientThread(client); //Создаем новый поток, которому передаем сокет > > catch (SocketException e) < System.err.println(«Socket exception»); e.printStackTrace(); >catch (IOException e) < System.err.println(«I/O exception»); e.printStackTrace(); >> >

Читайте также:
Программа цифровой рубль что такое

Думаю, данный код, пока что, не нуждается в комментариях. Я не стал особо заморачиваться на обработке исключений, но нам ведь не это важно, верно?

Ах да, мы же хотели получать номер порта из конфигурационного файла. Создадим для конфига отдельный класс, в котором будем хранить статические поля — параметры нашего чата.

Удобнее всего хранить параметры в properties-файле, благо Java предоставляет удобный интерфейс для работы с ними.

Итак, наш properties-файл будет состоять всего из одной строки (пока что)

PORT=1234

Config.java

package anexroid.server import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Properties; public class Config < private static final String PROPERTIES_FILE = «./server.properties»; public static int PORT; static < Properties properties = new Properties(); FileInputStream propertiesFile = null; try < propertiesFile = new FileInputStream(PROPERTIES_FILE); properties.load(propertiesFile); PORT = Integer.parseInt(properties.getProperty(«PORT»)); >catch (FileNotFoundException ex) < System.err.println(«Properties config file not found»); >catch (IOException ex) < System.err.println(«Error while reading file»); >finally < try < propertiesFile.close(); >catch (IOException ex) < ex.printStackTrace(); >> > >

Вся загрузка параметров происходит в блоке статической инициализации, поскольку полноценный конструктор в нашем случае — непозволительная роскошь.

Осталось только заменить в Server.java
ServerSocket socketListener = new ServerSocket(«1234»); на ServerSocket socketListener = new ServerSocket(Config.PORT); и добавить нужные import’ы

В дальнейшем, import’ы в коде буду упускать, поскольку любая IDE их сама подставит.

Итак, мы написали new ClientThread(); . Но что это такое, пока не решили. Пора исправить это.

Этот класс у нас будет отвечать за прием и передачу сообщений между клиентом и сервером, а значит, самый главный класс в чате — именно ClientThread.

Поскольку он работает в отдельном потоке, первое, что мы должны сделать — написать

public class ClientThread extends Thread < private Socket socket; public ClientThread(Socket socket) < this.socket = socket; this.start(); >public void run()

А теперь подумаем, что же написать в методе run().
Итак, по порядку. Для начала, мы должны получить от клиента информацию «Ты кто такой?» в противном случае — «Давай, до свидания!». Как только мы узнали кто он такой, мы должны отправить ему последние сообщения в нашем чате.

Далее, периодически, мы должны его ping’овать его каким-нибудь запросом, чтобы убедиться, что не ведем общение с трупом.

Затем, мы должны получать от него сообщения, о которых должны уведомлять всех подключенных клиентов.

Ну и, как только мы перестали получать от него запросы — клиента следует удалить из списка доступнх пользователей.

На время забудем о ClientThread, а задумаемся «Каким образом будет происходить общение?»
Мы уже решили, что будем передавать сериализованный объект. Итак, чтоже должно быть в этом объекте?

Я остановился на следующем варианте:
1. Логин пользователя, отправившего это сообщение (или Server-Bot)
2. Собственно, само сообщение
3. Время отправки
4. Список доступных серверу клиентов (для отображения у пользователя)

Для успешной сериализации/десериализации, класс в клиенте и сервере должен быть одинаковым. Поэтому позаботимся сразу и о том, и о другом.

Message.java

public class Message implements Serializable < private String login; private String message; private String[] users; private Date time; //Конструктор, которым будет пользоваться клиент public Message(String login, String message)< this.login = login; this.message = message; this.time = java.util.Calendar.getInstance().getTime(); >//Конструктор, которым будет пользоваться сервер public Message(String login, String message, String[] users) < this.login = login; this.message = message; this.time = java.util.Calendar.getInstance().getTime(); this.users = users; >public void setOnlineUsers(String[] users) < this.users = users; >public String getLogin() < return this.login; >public String getMessage() < return this.message; >public String[] getUsers() < return this.users; >public String getDate() < Time tm = new Time(this.time.getTime()); return tm.toString(); >>

Думаю, всё очевидно. Также, помимо сообщений мы хотим передавать нечто вроде ping’ов.

Ping.java

public class Ping extends Message < public Ping() < super(«ping», «ping»); >>

По сути, этот класс нам не сильно-то нужен, просто потом код будет удобнее читать

Итак, приступим к написанию ClientThread

ClientThread.run()

Код немного комментирован, поэтому все должны разобраться. Осталось дописать только несколько функций.
Итак, начнем по порядку.

Данная функция рассылает какое-то сообщение всем клиентам

ClientThread.broadcast()

private void broadcast(ArrayList clientsArrayList, Message message) < try < for (Client client : clientsArrayList) < client.getThisObjectOutputStream().writeObject(message); >> catch (SocketException e) < System.out.println(«in broadcast: » + login + » disconnected!»); getUserList().deleteUser(login); this.broadcast(getUserList().getClientsList(), new Message(«System», «The user » + login + » has been disconnected», getUserList().getUsers())); timer.stop(); >catch (IOException e) < e.printStackTrace(); >>

Ах да, мы еще забыли вписать некоторые поля класса ClientThread, которые активно использовали. Итак, класс ClientThread,java целиком

ClientThread.java

Осталось разобраться с функциями getUserList() и getChatHistory
Для начала, определим еще 3 класса

Client.java

public class Client < private Socket socket; private ObjectOutputStream oos; private ObjectInputStream ois; public Client(Socket socket)< this.socket = socket; >public Client(Socket socket , ObjectOutputStream oos , ObjectInputStream ois ) < this.socket = socket; this.oos = oos; this.ois = ois; >public Socket getSocket() < return this.socket; >public ObjectOutputStream getThisObjectOutputStream() < return this.oos; >public ObjectInputStream getThisObjectInputStream() < return this.ois; >public void setThisObjectOutputStream(ObjectOutputStream oos) < this.oos = oos; >public void setThisObjectInputStream(ObjectInputStream ois) < this.ois = ois; >>
UserList.java

public class UsersList < private MaponlineUsers = new HashMap(); public void addUser(String login, Socket socket, ObjectOutputStream oos, ObjectInputStream ois) < System.out.println( login +» connected» ); if (!this.onlineUsers.containsKey(login)) < this.onlineUsers.put(login , new Client(socket, oos, ois)); >else < int i = 1; while(this.onlineUsers.containsKey(login)) < login = login + i; i++; >this.onlineUsers.put(login , new Client(socket, oos, ois)); > > public void deleteUser(String login) < this.onlineUsers.remove(login); >public String[] getUsers() < return this.onlineUsers.keySet().toArray(new String[0]); >public ArrayList getClientsList() < ArrayListclientsList = new ArrayList(this.onlineUsers.entrySet().size()); String s = «»; for(Map.Entry m : this.onlineUsers.entrySet()) < clientsList.add(m.getValue()); System.out.println(m.getKey()); s = s + m.getKey(); >return clientsList; > >
ChatHistory.java
public class ChatHistory implements Serializable < private Listhistory; public ChatHistory() < this.history = new ArrayList(Config.HISTORY_LENGTH); > public void addMessage(Message message) < if (this.history.size() >Config.HISTORY_LENGTH) < this.history.remove(0); >this.history.add(message); > public List getHistory() < return this.history; >>

По сути, сервер готов к работе, осталось только немного модифицировать 2 класса.

Server.java

public class Server < private static UsersList list = new UsersList(); private static ChatHistory chatHistory = new ChatHistory(); public static void main(String[] args) < try < //Создаем слушатель ServerSocket socketListener = new ServerSocket(«1234»); while (true) < Socket client = null; while (client == null) < client = socketListener.accept(); >new ClientThread(client); //Создаем новый поток, которому передаем сокет > > catch (SocketException e) < System.err.println(«Socket exception»); e.printStackTrace(); >catch (IOException e) < System.err.println(«I/O exception»); e.printStackTrace(); >> public synchronized static UsersList getUserList() < return list; >public synchronized static ChatHistory getChatHistory() < return chatHistory; >>

Методы getChatHistory() и getUserList() сделаны синхронизированными, потому что с ними могут работать несколько потоков

И, доделаем наш конфиг, так как у нас добавились некоторые параметры

server.properties
PORT=5000
HISTORY_LENGTH=50
HELLO_MESSAGE=User join to the chat(Auto-message)
Config.java

public class Config < private static final String PROPERTIES_FILE = «./server.properties»; public static int PORT; public static int HISTORY_LENGTH; public static String HELLO_MESSAGE; static < Properties properties = new Properties(); FileInputStream propertiesFile = null; try < propertiesFile = new FileInputStream(PROPERTIES_FILE); properties.load(propertiesFile); PORT = Integer.parseInt(properties.getProperty(«PORT»)); HISTORY_LENGTH = Integer.parseInt(properties.getProperty(«HISTORY_LENGTH»)); HELLO_MESSAGE = properties.getProperty(«HELLO_MESSAGE»); >catch (FileNotFoundException ex) < System.err.println(«Properties config file not found»); >catch (IOException ex) < System.err.println(«Error while reading file»); >finally < try < propertiesFile.close(); >catch (IOException ex) < ex.printStackTrace(); >> > >

Заключение

Теперь наш сервер готов к использованию. Мы познакомились с сериализацией объектов и работой с сокетами в Java.

В следующей статье (завтра-послезавтра) мы напишем клиент для нашего чата, а пока жду комментариев, особенно относительно устройства чата, в частности — «Здесь абсолютно неправильно реаизовано XXX» (разумеется, жду только аргументированных оценок)

В любом случае, данная статья не призвана стать эталоном написания чата на Java, это лишь инструмент для понимания как вообще создавать такие приложения на хорошем примере, а не на эхо-чате в 10 строк.

Рекомендованный контент

Все ясно, но проблема NetBeans ругается 🙁 Можно мне архив с сорсами?)
Ты нашел решение проблемы?
Поддержу вышеотписавшегося, можете ли дать ссылку на проет?

у меня осталась одна ошибка вот в этом месте this.timer = new Timer(DELAY, new ActionListener() < , как её исправить?

Читайте также:
Программа по стимулированию роста занятости это

то Игорь: Подключайте таймер из библиотеки awt.
Вопрос к автору: где клиент.
Ребят, автор выложил клиент или нет еще?

У socketListener в конструкторе указан порт в виде String.Надо бы исправить.
ServerSocket socketListener = new ServerSocket(“1234”);

у кого-нидь была проблема с timer.stop()?
как ее решить?
getUserList() не видит этот метод, предлагает его объявить.Что делать?
Где продолжение? Ссылку, пожалуйста.

Перелыл весь сайт так и не нашел продолжения этой хорошей статьи! Может кто нибудь подскажет. дайте ссылку плизззз…..

Не знаю кому там всё ясно, но код вообще трудно читабельный. Пояснений во второй части вообще нету. Некоторые методы вообще вызываются не пойми как , так как находятся вне зоны видимости.

Хотя если не пытаться вдаваться в код, а просто понять общий принцип работы, то более менее понятно
Ну и где продолжение
Где клиент?
хорошая статья, а вот продолжение где?
В пакете java.awt я не нашел ни одного таймера…

Алекс надо смотреть тут import java.awt.event.*; К слову я что-то не догоняю о почему не видно вызовы getUserList и getChatHistory ? в какой класс зырить ?

В Server, там они определены. Просто из ClientThread они не видны…
Ребята кто-нибудь написал клиент к этому серверу? Поделитесь, у меня постоянно ошибки вылетают.

Вопрос автору: а как поведёт себя сервер, если будет 10 000 000+ клиентов онлайн? сервак от количества потоков не упадёт? и сколько надо оперативной памяти под это? и ещё один вопрос не лучше ли сообщения передавать в хотя бы xml формате, на серваке брать парсером его статус(ping | text | login |…) и дальше зависимости от статуса его обрабатывать или всё таки лучше сериализованный объект передавать и на сервере не парсить а десериализовывать?

Где можно найти клиент?
ThreadClient не очень написан. Запускать поток в конструкторе как-то не очень.
Что бы не было ошибки связанной с с timer.stop() надо подключить import javax.swing.Timer;
Проблема с классом СlientTread.
Искал ошибки, но не нашел

ServerSocket socketListener = new ServerSocket(Config.PORT);
Не пойму почему ругается, в классе Server проблема, почему то не видит в классе config, не могли бы вы помочь разобраться?

В классе ClientThread не видит методы getChatHistory и getUserList. Как решить проблему?
_Кибер_Кукумбер_ :

Эти методы находятся в классе Server, и являются статическими. Вызываются так: Server.getChatHistory(), Server.getUserList().

порт в кавычках. мдаааааа….бб ламер
в общем иди нахер…твой код безнадежно устарел…в топку его и тебя
_Кибер_Кукумбер_ :

Новости

  • На Huawei Mall появились умные костыли Linky Healthy Crutches с экраном, гироскопом, отслеживанием активности и корпусом из аэрокосмического алюминиевого сплава
  • 22 000 мА•ч, камера Samsung 48 Мп и стилус в комплекте, недорого. Стартовали продажи флагманского неубиваемого планшета Blackview Active 8 Pro
  • Это одно из самых быстрорастущих приложений в истории: в Threads уже более 100 млн пользователей
  • «Практически невозможно», чтобы гарнитуры Apple Vision в обозримом будущем догнали по продажам iPad
  • Названы причины возвращения айтишников в Россию: это стоимость жилья и зарплата
  • «У нас была утечка тел, а не мозгов», — 85% айтишников вернулись в Россию
  • Следить за Илоном Маском и его частным самолётом теперь можно в Threads
  • МТС закрыла проект голосового помощника «Марвин»

Актуальные темы

Архив

  • Июль 2023 (181)
  • Июнь 2023 (553)
  • Май 2023 (607)
  • Апрель 2023 (608)
  • Март 2023 (589)
  • Февраль 2023 (604)
  • Январь 2023 (702)
  • Декабрь 2022 (670)
  • Ноябрь 2022 (807)
  • Октябрь 2022 (686)

Источник: www.pvsm.ru

Основы программирования TCP-сокетов на Java

Java

Клиент-серверная архитектура — наиболее распространенная структура приложений в Интернете. В этой архитектуре клиенты (т.е. персональные компьютеры, устройства Интернета вещей и т. д.) сначала запрашивают ресурсы с сервера. Затем сервер отправляет обратно соответствующие ответы на запросы клиентов. Чтобы это произошло, должен быть какой-то механизм, реализованный как на стороне клиента, так и на стороне сервера, который поддерживает эту сетевую транзакцию. Этот механизм называется коммуникацией посредством сокетов.

Почти каждое приложение, которое полагается на сетевые операции, такие как извлечение данных с удаленных серверов и загрузка файлов на сервер, широко использует сокеты “под капотом”. Несколько примеров таких приложений — браузеры, чат-приложения и одноранговые сетевые приложения.

В этой статье мы более подробно рассмотрим сокеты и простую клиент-серверную реализацию с использованием сокетов в Java.

Примечание: существует два типа сокетов: TCP и UDP. Поскольку большинство сетевых приложений используют TCP, здесь я буду говорить только о TCP-сокетах и их реализации.

Что такое сокет?

Сокет — это программная (логическая) конечная точка, устанавливающая двунаправленную коммуникацию между сервером и одной или несколькими клиентскими программами. Сокет — это нечто “программное”. Другими словами, сокет не существует на физическом уровне. Прикладное программное обеспечение определяет сокет так, чтобы он использовал порты на основном компьютере для его реализации. Это позволяет программистам комфортно работать с низкоуровневыми деталями сетевых коммуникаций, такими как порты, маршрутизация и т. д., внутри прикладного кода.

Как работают сокеты?

TCP-сокет устанавливает связь между клиентом и сервером в несколько этапов.

  • Socket() — на сервере создается конечная точка для коммуникации.
  • Bind() — сокету присваивается уникальный номер и для него резервируется уникальная комбинации IP-адреса и порта.
  • Listen() — после создания сокета сервер ожидает подключения клиента.
  • Accept() — сервер получает запрос на подключение от клиентского сокета.
  • Connect() — клиент и сервер соединены друг с другом.
  • Send()/Recieve() — обмен данными между клиентом и сервером.
  • Close() — после обмена данными сервер и клиент разрывают соединение.

На каждой из перечисленных выше стадий коммуникации сокетов “под капотом» происходит много всего сложного. Однако этих знаний вполне достаточно для понимания и демонстрации того, как работает коммуникация посредством TCP-сокетов.

К настоящему времени мы уже достаточно знаем о TCP-сокетах. Давайте теперь посмотрим на них в действии.

Реализация коммуникации посредством TCP-сокетов в Java

Давайте посмотрим, как мы можем реализовать коммуникацию сокетов в Java. Мы сейчас напишем две Java-программы. Одной будет программа, запущенная на сервере, а другой — клиентская программа, которая будет взаимодействовать с сервером.

Реализация серверного сокета

import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class SocketServer < public static final int SERVER_PORT = 50001; public static void main (String[] args)< try < ServerSocket server = new ServerSocket(SERVER_PORT); Socket clientConn = server.accept(); DataOutputStream serverOutput = new DataOutputStream(clientConn.getOutputStream()); serverOutput.writeBytes(«Java revisitedn»); clientConn.close(); >catch (IOException e) < e.printStackTrace(); >> >

В приведенной выше программе сервер открывает сокет с порта 50001 на серверной машине и ожидает клиента на server.accept() . После подключения клиента создается экземпляр выходного потока. Это может быть использовано для отправки данных с сервера на подключенный клиент. Именно это и делает serverOutput.writeBytes() . После отправки данных соединение с клиентом завершается.

Теперь давайте создадим клиент для взаимодействия с серверным сокетом, созданным выше.

Реализация клиентского сокета

import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.net.Socket; public class SocketClient < public static void main(String[] args)< try < Socket clientSocket = new Socket («localhost»,50001); InputStream is = clientSocket.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String receivedData = br.readLine(); System.out.println(«Received Data: «+receivedData); >catch (Exception e) < e.printStackTrace(); >> >

Показанная выше программа действует как клиент, создавая соединение с серверным сокетом. После подключения клиент получает отправленные сервером данные. Входной поток соединяется с буфером, используя BufferedReader для хранения полученных данных, так как мы не можем быть уверены, что данные будут использоваться сразу же после получения. Затем мы считываем данные из буфера и выводим их в консоль.

Запуск программ

Сначала запустите серверную Java-программу, а затем клиентскую Java-программу (потому что сервер уже должен работать для подключения клиента). Вы увидите Received data: Java Revisited в терминале, где работает клиентская программа. Вот что здесь произошло: серверная программа отправила данные клиенту по запросу, а клиентская программа вывела их на терминал.

В этой статье мы обсудили, что такое сокеты и Java-реализация связи TCP-сокетов.

Спасибо за чтение.

  • Кто на свете всех сильнее — Java, Go и Rust в сравнении
  • Java-Lombok: нужны ли геттеры и сеттеры?
  • Топ — 9 фреймворков Java в 2020 году

Источник: nuancesprog.ru

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru