Top-office11.ru

IT и мир ПК
2 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Socket close java

Пакет java.net, ServerSocket

На сегодняшний день использование клиентов служб мгновенного обмена сообщениями (instant messanger) стало незаменимым средством для всех пользователей Интернета. Существует множество клиентов (Skype, WhatsApp, Viber, ICQ и т. д.), о которых каждый слышал и которые мы ежедневно используем. Все они работают по определенным правилам, т.е. реализуют определенные протоколы взаимодействия.

Наиболее распространенный протокол HTTP (Hyper Text Transfert Protocol) определяет взаимодействие двух программ, клиента и сервера, которые могут быть запущены на разных и удаленных друг от друга машинах. Клиентом является приложение, которое пользуется каким-то сервисом, предоставляемым сервером, обычно размещенном на удаленном компьютере. Клиент должен подключиться к удаленному серверу, который постоянно находится в режиме ожидания соединения. После этого они могут обмениваться информацией.

HTTP использует протокол TCP/IP. В статье рассмотриваются возможности, предоставляемые Java для работы с этим протоколом.

Распределение протоколов по уровням модели TCP/IP

№ п.п.НазваниеПротоколы
5ПрикладнойHTTP, RTP, FTP, DNS
4ТранспортныйTCP, UDP, SCTP, DCCP
3СетевойIP. Вспомогательные протоколы, вроде ICMP и IGMP, работают поверх IP.
4КанальныйEthernet, IEEE 802.11 Wireless Ethernet, SLIP, Token Ring, ATM и MPLS
5ФизическийФизическая среда и принципы кодирования информации, T1, E1

Протокол HTTP располагается на прикладном уровне и использует для собственной реализации протоколы более низких уровней. Основой HTTP является протокол транспортного уровня TCP.

Согласно протоколу IP (Internet Packet), каждый узел (компьютер, switch и т.п.) в сети имеет свой IP-адрес. На данный момент интернет работает по протоколу IPv4, где IP адрес записывается 4 числами от 0 до 255 — например, 127.0.0.1. Существует и другой способ идентификации компьютеров в сети через доменное имя, которое более удобное и нагляднее идентифицирует компьютер, чем простой набор чисел (например, java-oline.ru). В Интернете существуют специальные сервера DNS (Domain Name System), которые осуществляют преобразование доменного имени в IP-адрес и наоборот.

TCP протокол базируется на IP для доставки пакетов, но добавляет два важных свойства :

  • установление соединения между приложениями;
  • использование портов, а не просто узлов.

Таким образом, для идентификации компьютера (host’a) в сети используется IP-адрес; для идентификации приложения TCP добавляет понятие порта. Порт — это целое число от 1 до 65535 указывающее, какому приложению предназначается пакет.

Java для работы в сети имеет специальный пакет java.net, содержащий класс Socket, что в переводе означает «гнездо». Ключевыми классами для реализации взаимодействия программ по протоколу TCP являются :

  • java.net.ServerSocket — класс реализует серверный сокет, который ожидает запросы, приходящие от клиентов по сети, и может отправлять ответ.
  • java.net.Socket — класс реализует клиентский сокет.

Серверный сокет ServerSocket

Для создания серверного сокета ServerSocket можно использовать один из следующих конструкторов :

Первым параметров в конструктор необходимо передать порт port, который будет привязан к серверному сокету. Если порт занят или запрещён к использованию политикой безопасности компьютера, то вызывается исключение IOException. Если значение передавамого порта равно 0, то система сама выделит номер свободного порта. Значение полученного порта можно узнать через вызов функции getLocalPort(). Несвязанный серверный сокет ServerSocket() необходимо «связывать» с IP-адресом и портом (см. ниже метод bind).

Параметр backlog устанавливает максимальное количество клиентских подключений. Если количество подключений достигло предела, то следующему клиенту в подключении будет отказано.

Для работы с IP-адресами в библиотеке Java имеется класс java.net.InetAddress, который используется в третьем конструкторе ServerSocket. С помощью InetAddress можно определить адрес IP локального узла, а также адреса удаленного узла, заданного доменным именем. Наиболее распространенные методы класса InetAddress :

При разработке сетевых приложений на начальном этапе, как правило, используют один компьютер (host). Для этого создатели протокола IP определили специальный адрес, называемый localhost — это IP-адрес «локальной заглушки (local loopback)» для работы приложений без использования сети. Общий порядок получения этого адреса в Java следующий :

Если методу getByName() передать значение null, то по умолчанию будет использоваться localhost. Cодержимым InetAddress нельзя манипулировать. Для создания InetArddress можно использовать один из перегруженных статических методов класса getByName(), getAllByName() или getLocalHost().

Методы серверного сокета

В таблице представлены наиболее часто используемые методы серверного сокета ServerSocket.

МетодОписание
Socket accept()Ожидание подключения клиента
void bind(SocketAddress endpoint)Связывание ServerSocket c определенным адресом (IP-адрес и порт)
void close()Закрытие сокета
ServerSocketChannel getChannel()Получение объекта ServerSocketChannel, связанного с сокетом
InetAddress getInetAddress()Получение локального адреса сокета сервера
int getLocalPort()Получение номера порта, который серверный сокет слушает
SocketAddress getLocalSocketAddress()Получение адреса серверного сокета в виде объекта SocketAddress
int getReceiveBufferSize()Получение размера буфера серверного сокета
boolean isClosed()Проверка, закрыт ли серверный сокет
void setReceiveBufferSize(int size)Определение размера буфера серверного сокета

После создания в приложении серверного сокета ServerSocket необходимо вызвать функцию accept(), которая переводит приложение в режим ожидания подключения клиента. Дальнейший код не выполняется, пока клиент не подключится. Как только клиент подключается функция возвращает объект класса java.net.Socket, который следует использовать для взаимодействия сервера с клиентом.

Клиентский сокет Socket

Коиентский сокет Socket можно создать с использованием одного из следующих конструкторов :

В строковой константе host можно указать как IP адрес сервера, так и его DNS имя. При этом программа автоматически выберет свободный порт на локальном компьютере и свяжет его с сокетом. При этом могут быть вызваны одно из двух видов исключений, связанного с неизвестным адресом хоста (в сети компьютер не будет найден) или отсутствием связи с этим сокетом.

Класс Socket имеет один интересный метод setSoTimeout :

Метод setSoTimeout устанавливает время ожидания (timeout) для работы с сокетом. Если в течение этого времени никаких действий с сокетом не произведено (получение и отправка данных), то он самоликвидируется. Время задаётся в секундах, при установке timeout равным 0 сокет становится «вечным».

Примеры использования SocketServer и Socket

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

Листинг сервера

Сервер создает сокет ServerSocket, открывает порт и ждет подключений клиента. После подключения клиента сервер формирует отдельный поток Thread, в который передает порядковый номер клиента и сокет Socket для обмена сообщениями с клиентом. Сам сервер продолжает ожидать подключение следующего клиента.

Здесь следует отметить немаловажную особенность серверного приложения : оно может обслуживать сразу несколько клиентов одновременно. Теоретически, количество одновременных подключений неограниченно, но практически всё упирается в мощность компьютеров. Эта проблема конечной мощности компьютеров используется в DOS атаках на серверы: их просто закидывают таким количеством подключений, что компьютеры не справляются с нагрузкой и «падают».

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

Читать еще:  Справочник javascript pdf

Листинг клиента

Клиентский пример использования класса java.net.Socket для подключения к серверу и обмена с ним сообщениями. Если серверу отправить сообщение «quit», то цикл обмена сообщениями будет прекращен, сервер закроет подключение (свой сокет) и клиентский сокет также следует закрыть.

Тестирование приложений

Результаты тестирования серверного и клиентского приложений будут выводиться в соответствующие «консоли». После подключения клиента к серверу он может отправлять сообщения. Сервер возвращает изменное сообщение клиента. Одновременно к серверу может подключиться несколько клиентов.

Сообщения сервера

Сервер после старта выводит соответствующее сообщение и ждет подключений клиентов. После подкючения клиента и получения от него сообщения сервер возвращает клиенту измененную строку. При получении сообщения «quit» сеанс завершается.

Сообщения клиента

После подключения клиента к серверу выводится информация о сокете. Далее серверу отправляется сообщение «Привет». Сервер информирует клиента, что получил это сообщение. При отправлении текста «quit» сеанс обмена сообщениями с сервером завершается.

Скачать примеры

Рассмотренные на странице примеры использования ServerSocket, Socket для создания сетвых приложений в виде проекта Eclipse можно скачать здесь (24.8Кб).

Java socket framework

Всем доброго времени суток. Разрабатываю онлайн 3д-игру, была выбрана платформа java. Для 3d был выбран движок jmonkeyengine. А в качестве серверной части я решил написать простеньки p2p фреймворк, MVC с реализацией представлений на клиенте.

Где может пригодится:

1. Сервер для мобильных сервисов.
2. Любые многопользовательские приложения где нужно p2p.
3. Онлайн игры.
4. Торрент при желании.

Диаграмма:

1. Клиент посылает на сервер сообещение в котором перечисляются переменные и какую задачу вызвать.
2. Сообщение попадает очередь входящих сообщений.
3. Роутер запускает нужную задачу с этими переменными.
4. В задаче мы отправляем ответ пользователю.

1. Настраивать порты клиента и сервера.
2. Модели базы данных.
3. Валидация входящих сообщений.
4. Права пользователей.
5. Модули.
6. Механизм сессий.
7. Команды.
8. Смена протокола tcp/udp.

Инструкции, примеры и документациия

Пример отправки и приема сообщений

1. Клиента посылает на сервер json строку c названием вызываемой задачи.
2. Задача извлекает переменные из сообщения и посылает ответ.

Задача должна быть создана в папке tasks и унаследованна от JClientTask. В конструкторе должна передаваться класс JInMessages с входящим сообщением. Должны быть реализованы методы rules,rights,action. В rules описаны правила валидации переменных, можно написать свои правила валидации. В rights перечисление прав пользователей которые имеют право вызывать действие.
в action основной код.

Строка ответа и поставнока в очередь

Вместо ip можно ставить любой ip который слушает сокет и ждет json строку.

После установки фремворка по инструкции в базе будут 2 таблицы: Users, Session. Примеры использования есть в папках с задачами.

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

1. Права должны быть описаны в задачах в методе rights:guest,user,admin. Неавторизованный пользовател имеет права guest. Зарегистрированнному пользователю присваивается user, эти значения хранятся в базе данных в таблице rights.

Пример: авторизация по токену, модели, права

1. В права указываем ожидаемые переменные:email,password.
2. Создаем модель Users, вызываем метод авторизации.
3. Создаем модель сессии — получаем токен.
4. Отправляем ответ.
5. Токен сохраняем на клиенте.

Пример проверки прав и отправки сообщений на определенный ip

1. В правах указываем user.
2. В ожидаемых переменных token

После вызова задачи с токеном и правами «не гость». Пользователь ищется в базе данных в таблице Session, по user_id создается модель Users — которая доступнав задаче в переменной webUser.

Можно отправлять сообщения всем клиентам по user_id в Session или по соединениею в классе JConnections.

Java Socket tutorial

Java Socket tutorial shows how to do network programming in Java with sockets. Socket programming is low-level. The purpose of the tutorial is to introduce network programming including these low-level details. There are higher-level APIs that might be better suited for a real task. For instance, Java 11 introduced HttpClient and Spring has Webclient.

Java Socket

In programming, a is an endpoint of a communication between two programs running on a network. Socket classes are used to create a connection between a client program and a server program. The Socket represents the client socket, and the ServerSocket the server socket.

A ServerSocket is bound to a port number, which is a unique Id through clients and servers aggree to communicate.

Socket and ServerSocket are used for the TCP protocol. The DatagramSocket and DatagramPacket are used for the UDP protocol.

TCP is more reliable, has extensive error checking, and requires more resources. It is used by services such as HTTP, SMTP, or FTP. UDP is much less reliable, has limited error checking, and requires less resources. It is used by services such as VoIP.

DatagramSocket is a socket for sending and receiving datagram packets. A datagram packet is represented by DatagramPacket class. Each packet sent or received on a datagram socket is individually addressed and routed. Multiple packets sent from one machine to another may be routed differently, and may arrive in any order.

Java Socket Time Client

The are servers that provide current time. A client simply connects to the server with no commands, and the server responds with a current time.

In our example, we have chosen a server in Sweden.

The example connects to a time server and receives the current time.

This is a time server from Sweden; the 13 port is a standard port for daytime services.

A stream client socket is created. It is connected to the specified port number on the named host. The socket is automatically closed with Java’s try-with-resources statement.

The getInputStream() returns an input stream for this socket. We read the server’s response from this input stream. The communication between sockets is in bytes; therefore, we use the InputStreamReader as a bridge between bytes and characters.

Since the response message is small, we can read it character by character with little performance penalty.

Java Socket Whois Client

Whois is a TCP-based transaction-oriented query/response protocol that is widely used to provide information services to Internet users. It is used to query information such as domain name or IP address block owners.

Whois protocol uses port 43.

In the example, we probe for information about the owners of a domain name.

Читать еще:  Alert javascript переменная

We get an output stream for the socket and wrap it into a PrintWriter . PrintWriter will convert our character into bytes. With println() , we write the domain name to the stream. Communication through sockets is buffered. The second parameter of the PrintWriter is autoFlush ; if set to true , the buffer will be flushed after each println() .

The response from the server is read and written to the console.

Java Socket GET Request

In the following example, we create a GET request. The HTTP GET request is used to retrieve a specific resource.

The example retrieves an HTML page from a website.

We open a socket on the specified webpage on port 80. Port 80 is used by HTTP protocol.

We are going to issue text commands on the protocol; therefore, we create a PrintWriter for the socket output stream. Since we do not set the autoFlush option to true , we need to manually flush the buffer.

We create an HTTP GET request, which retrieves the home page of the specified webpage. Notice that the text commands are finished with rn (CRLF) characters. These are necessary communication details which are described in RFC 2616 document.

The shutdownOutput disables the output stream for this socket. This is necessary to close the connection in the end.

For the server response, we open a socket input stream and use InputStreamReader to translate bytes to characters. We also buffer the reading operation.

We read the data line by line.

Finally, we shut down the input stream as well.

Java Socket HEAD Request

In the next example, we create a HEAD request with a Java socket. The HEAD method is identical to the GET method except that the server does not return a message body in the response; it returns only the header.

The example retrieves the header of the specified web page.

We issue a HEAD command.

In HTTP protocol version 1.1, all connections are considered persistent (keep-alive) unless declared otherwise. By setting the option to false , we inform that we want to finish the connection after the request/response cycle.

Java ServerSocket DateServer

The following example creates a very simple server with ServerSocket . ServerSocket creates a server socket, bound to the specified port.

The example creates a server that returns the current date. The program must be manually killed in the end.

A server socket on port 8081 is created.

The accept() method listens for a connection to be made to this socket and accepts it. The method blocks until a connection is made.

We write the current date to the socket output stream.

We have a Python script that issues a GET request to the server.

This is the output.

Java Socket Client/Server Example

In the following example, we have a server and a client. The server reverses the text sent from a client. The example is simple and blocking. To improve it, we need to include threads.

The ReverseServer sends a reversed string back to the client. It communicates only with one client at a time. It must disconnect from a client first to communicate with another client. It receives a bye command from a client to close the connection.

We have a socket input stream for reading client data and socket output stream for sending the response back to the client; the output streams and the connection are closed.

A do-while loop is created for a single client. We read the data from the client and send the modified content back. The loop is finished upon receiving a bye command from the client. Before this is done, no other client can connect to the server.

The client sends text data to the server.

We read input from the console and send it to the server. The while loop is finished when we send the bye command, which informs the server that the connection can be closed.

Java DatagramSocket example

UDP is a communication protocol that transmits independent packets over the network with no guarantee of arrival and no guarantee of the order of delivery. One service that used UDP is the Quote of the Day (QOTD).

The following example creates a client program that connects to a QOTD service.

The example retrieves a quote from a quote service and prints it to the terminal.

We get an IP address from a hostname.

A DatagramSocket is created.

A DatagramPacket is created. Since the QOTD service does not require data from a client, we send an empty small array. Each time we send a packet, we need to specify data, address, and the port.

The packet is send to its destination with send() .

We receive a packet from the service.

We transform the received bytes into a string and print it.

In this tutorial, we have created network Java programs with sockets. You might also be interested in the related tutorials: Java HTTP GET/POST request tutorial, Java InputStreamReader tutorial, Java Servlet tutorial, and Java tutorial.

Программирование сокетов на Java

категория
Java
дата16.07.2009
авторbioflash
голосов85

[Disclaimer: Данная статья была переведена в рамках «Конкурса на лучший перевод статьи» на сервисе Quizful. Ссылка на оригинал находится внизу страницы.]

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

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

На сегодняшний день использование клиентов служб мгновенного обмена сообщениями (instant messanger) стало незаменимым средством для всех пользователей Интернета. Существует множество различных протоколов и клиентов (MSN, ICQ, Skype и т. д.), о которых каждый слышал и которые мы все ежедневно используем. Но не все знают, что положено в основу их роботы – собственно для этого статья и написана. Предположим, вы установили один из клиентов служб мгновенного обмена сообщениями на ваш компьютер. После его запуска и введения имени и пароля вашего пользователя, программа пытается подключиться к серверу. Что именно означает слово «подключиться»?

Каждый компьютер в сети имеет IP-адрес. Этот адрес похож на ваш домашний адрес – он однозначно идентифицирует ваш компьютер и позволяет другим общаться с вашим компьютером. Не будем вдаваться в подробности IP-адреса, так как эта статья не о них, хочу только отметить что IP-адрес это набор номеров разделенных точками (например, 64.104.137.158). Хотя существует и другой способ идентификации компьютеров в сети – доменное имя, которое более удобное и нагляднее идентифицирует компьютер, чем простой набор чисел (например, www.quizful.net). В Интернете существуют специальные компьютеры, которые осуществляют преобразование доменного имени в IP-адрес и наоборот.

Читать еще:  Разработка приложений на javascript

На одном компьютере может параллельно исполняется несколько программ. Предположим, что вы запустили 10 программ на своем компьютере, и все они ожидают, чтоб другие компьютеры связались с ними. Можете представить себе это так: вас 10 человек в большом офисе с 1 телефоном и все ждут звонков от их собственных клиентов. Как вы это решите? Можно конечно назначить ответственного работника, и он будет приносить телефон соответственному человеку, которому звонят, но тогда другие клиенты не смогут дозвониться к другим людям. Кроме того, это очень трудно и нелепо иметь ответственного работника за маршрутизацию звонков к нужным людям. Вы должно быть, уже догадались, к чему я веду – если все эти программы, исполняющиеся на одном компьютере, с гордостью просят своих клиентов связаться с ними по определенному IP-адресу, то их клиенты не будут довольны. Идея состоит в следующем … иметь отдельный IP-адрес для каждой программы, верно? НЕ ВЕРНО! Суть вопроса не правильная – это также как спрашивать об отдельном офисе для каждого из вас. Ну, тогда … может отдельных телефонных номеров будет достаточно? ДА! На сетевом жаргоне «отдельные телефонные номера» имеют название порты. Порт – это просто число и каждая из программ, которая исполняется на определенном компьютере, может выбрать уникальное число порта, чтоб определить себя для внешнего мира. ЗАПОМНИТЕ – эти порты вы не сможете найти среди аппаратных средств компьютера (даже не старайтесь их искать). Эти числа – логические. Теперь все прояснилось: существует IP-адрес, с помощью которого другие компьютеры могут распознавать определенный компьютер в сети, и порт-число, которое определяет некую программу, работающую на компьютере. Также становиться понятным и то, что две программы на разных компьютерах могут использовать один и тот же порт (два дома на разных улицах тоже могут иметь один и тот самый номер, или нет?). Ну что же, мы практически у цели, только чтоб немного вас попугать, давайте выведем формулу:

Если сложить вместе выше описанные уравнения, то получим:

Если вы догадались до этого сами – значит мои усилия не пропали зря. Если нет, тогда прочитайте еще раз все сначала или воспользуйтесь Google для поиска лучшей статьи.

Подведем итог, сокет – это комбинация IP-адреса и порта. Сокет адрес надает возможность другим компьютерам в сети находить определенную программу, которая исполняется на определенном компьютере. Вы можете отображать сокет адрес вот так 64.104.137.58:80, где 64.104.137.58 – IP-адрес и 80 – порт.

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

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

1) Одна Джава программа будет пытаться связаться с другой Java программой (которая отчаянно ждет кого-то, чтоб с ней связался). Назовем первую программу Клиентом, а вторую Сервером.

2) После успешного связывания с сервером, клиент ждет ввода данных от вас и отсылает текст серверу.

3) Серверная программа отсылает клиенту назад тот ;t текст (для того чтоб показать, что она умеет делать даже такое полезное действие).

4) Полученный от сервера текст, клиент показывает вам, чтоб показать вам мнение сервера о вас. Приготовились приступить к разработке? Начнем. Отмечу только, что я не буду учить вас программированию на Java с чистого листа, а только объясню код, который относится к сокетам. Создайте 2 новых Джава программы и назовите их Server.java и Client.java. Я привел код ниже, только не пугайтесь, я все объясню.

Теперь скомпилируем код:

Откроем два командных окна (DOS). В одном окне введем:

Обязательно в таком порядке.

Теперь введите строку текста в окне, где запущен клиент, и нажмите кнопку Enter. Наблюдайте за двумя окнами и увидите что случиься. В конце, нажмите Ctrl-C для того чтоб остановить программы.

Объяснение кода работы с сокетами

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

Рассмотрим следующую часть кода сервера:

Класс ServerSocket немного отличается от класса Socket. Класс Socket – это и есть сокет. Главное отличие ServerSocket заключается в том, что он умеет заставлять программу ждать подключений от клиентов. Когда вы его создаете, нужно указывать порт, с которым он будет работать, и вызвать его метод accept(). Этот метод заставляет программу ждать подключений по указанному порту. Исполнение программы зависает в этом месте, пока клиент не подключится. После успешного подключения клиентом, создается нормальный Socket объект, который вы можете использовать для выполнения все существующий операций с сокетом. Заметим также, что этот Socket объект отображает другой конец соединения. Если вы хотите отослать данные клиенту, то вы не можете использовать для этого ваш собственный сокет.

Следующим рассмотрим Socket класс. Вы можете создать Socket объект, указав IP-адрес и порт. Вы можете использовать InetAddress класс для отображения IP-адреса (этот способ более предпочтительный). Для создания InetAddress объекта используйте следующий метод:

Заметим, что в нашей программе мы использовали адрес 127.0.0.1. Это специальный адрес называется адрес замыкания – он просто отображает локальный компьютер. Если вы намерены запустить клиент и сервер на разных компьютерах, тогда нужно использовать соответственный IP-адрес сервера.

После того как мы создали InetAddress, то можно создать Socket:

После создания Socket объекта, можно взять входной и выходной потоки сокета. Входной поток позволит вам читать с сокета, а выходной поток дает возможность писать в сокет.

Следующие строки просто конвертируют потоки в другие типы потоков. После этого нам легче будет работать с String объектами. Этот код ничего не делает с сетью.

Все остальное очень просто – простые манипуляции с объектами потоков (никаких сокетов). Вы можете использовать ваши любимые потоки, вызывать ваши любимые методы, и удостоверяться в передаче данных во второй конец. Если вы не очень осведомлены в использовании потоков, рекомендую вам найти статью о них и прочесть.

Если Вам понравилась статья, проголосуйте за нее

Голосов: 85 Голосовать

Ссылка на основную публикацию
Adblock
detector