Клиент-серверная архитектура в картинках

Введение

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

  1. С точки зрения «железа», веб-сервер — это компьютер, который хранит файлы сайта (HTML-документы, CSS-стили, JavaScript-файлы, картинки и другие) и доставляет их на устройство конечного пользователя (веб-браузер и т.д.). Он подключён к сети Интернет и может быть доступен через доменное имя, подобное .
  2. С точки зрения ПО, веб-сервер включает в себя несколько компонентов, которые контролируют доступ веб-пользователей к размещённым на сервере файлам, как минимум — это HTTP-сервер. HTTP-сервер — это часть ПО, которая понимает URL-адреса (веб-адреса) и HTTP (протокол, который ваш браузер использует для просмотра веб-страниц).

На самом базовом уровне, когда браузеру нужен файл, размещённый на веб-сервере, браузер запрашивает его через HTTP-протокол. Когда запрос достигает нужного веб-сервера («железо»), сервер HTTP (ПО) принимает запрос, находит запрашиваемый документ (если нет, то сообщает об ошибке ) и отправляет обратно, также через HTTP.

Чтобы опубликовать веб-сайт, необходим либо статический, либо динамический веб-сервер.

Статический веб-сервер, или стек, состоит из компьютера («железо») с сервером HTTP (ПО). Мы называем это статикой, потому что сервер посылает размещённые файлы в браузер как есть.

Динамический веб-сервер состоит из статического веб-сервера и дополнительного программного обеспечения, чаще всего сервера приложения и базы данных. Мы называем его динамическим, потому что сервер приложений изменяет исходные файлы перед отправкой в ваш браузер по HTTP.

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

JWT, разумеется

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

И он работает. Причём быстро и вполне надёжно.

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

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

Как вы реализуете истечение доступа для вашего пользователя, не дожидаясь, пока он выйдет сам? Быстрый способ — изменить ключ шифрования. Но подождите, это приведет к истечению срока действия всех токенов ваших пользователей… Есть другая идея. Может быть, интегрировать базу данных, которая содержит все просроченные ключи, и проверять по ней? Или, может быть, в базе будут все действительные ключи? Как было бы просто: сначала проверьте, действителен ли сам JWT, а затем проверьте по базе данных, не занесен ли он в черный список.

Но подождите, разве так не отправляются в мусор пресловутые преимущества JWT — “быстродействие, отсутствие необходимости обращения к базе данных, скорость проверок”? В некотором роде. Тогда, скажете вы, надо добавить кэширование, чтобы уменьшить серфинг по базе данных. Да, это сработает, но имейте в виду: кэш также необходимо разделять между несколькими экземплярами веб-сервера, и реализация должна быть отказоустойчивой, особенно для функций, связанных с безопасностью пользователя (к примеру, сброс пароля).

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

3 ответа

Лучший ответ

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

Чтобы поддерживать постоянство сеанса, в основном для балансировки нагрузки вставляйте идентификатор сервера в cookie при ответе клиенту (пожалуйста, обратите внимание, что cookie — это не функция браузера, а функция HTTP, определенная эта спецификация) и должна поддерживаться клиентом HTTP, который используется в Axis 1.4 ниже). Я предлагаю вам проанализировать, как работает ваш баланс нагрузки, и исходя из этого вам, возможно, придется изменить свои потребности, чтобы изменить своих клиентов

Если в вашем балансе нагрузки используется подход на основе файлов cookie, этот ответ может оказаться полезным

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

Надеюсь это поможет.

1

skadya
18 Окт 2017 в 22:21

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

Обычно липкий сеанс управляется балансировщиком нагрузки путем изменения cookie сеанса для добавления идентификатора сервера.

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

Gab
12 Окт 2017 в 12:45

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

Преимущества лиц без гражданства:

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

  • Экономит ресурсы сервера. Нам не нужно выделять память на стороне сервера (опять же — масштабируемость).

  • Не нужно восстанавливать после перезагрузки сервера.

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

Хорошее обсуждение вы можете найти здесь: Sticky и NON-Sticky сессии

Липкая сессия за и против: Плюсы и минусы загрузки Sticky Session / Session Affinity стратегия гашения?

Теперь перейдем к вашему вопросу:

Да, в липкой сессии.

Конфигурация сеанса вам нужна балансировка нагрузки / сервер, и он может обрабатывать любые старые или новые типы приложений

Нет его конфигурации вам нужно сделать на уровне сервера.

vaquar khan
9 Окт 2017 в 15:40

Сервер 1С:Предприятие на Ubuntu 16.04 и PostgreSQL 9.6, для тех, кто хочет узнать его вкус. Рецепт от Капитана

Если кратко описать мое отношение к Postgres: Использовал до того, как это стало мейнстримом.
Конкретнее: Собирал на нем сервера для компаний среднего размера (до 50 активных пользователей 1С).
На настоящий момент их набирается уже больше, чем пальцев рук пары человек (нормальных, а не фрезеровщиков).
Следуя этой статье вы сможете себе собрать такой же и начать спокойную легальную жизнь, максимально легко сделать первый шаг в мир Linux и Postgres.
А я побороться за 1. Лучший бизнес-кейс (лучший опыт автоматизации предприятия на базе PostgreSQL).
Если, конечно, статья придется вам по вкусу.

Специальные требования к серверу

В нашем случае лучше всего использовать сервер на основе цикла событий. Например, NodeJS, Kestrel или Twisted. Идея состоит в том, что при использовании потокового решения будет один поток на соединение. То есть, 1000 соединений = 1000 потоков. В решении на основе цикла событий у нас будет один поток для 1000 соединений.

  1. Вы можете принимать запросы EventSource только в том случае, если HTTP-запрос говорит, что он может принимать MIME-тип event-stream;
  2. Необходимо вести список всех подключенных пользователей, чтобы запускать новые события;
  3. Вы должны прослушивать сброшенные соединения и удалять их из списка подключенных пользователей;
  4. Вы должны поддерживать историю сообщений, чтобы при повторном подключении клиентов можно было отправить им пропущенные сообщения.

Мы получили все, чтобы приложение работало эффективно. Но столкнулись с некоторыми проблемами:

  • Устаревшие прокси-серверы в некоторых случаях удаляют HTTP-соединения после короткого таймаута. Чтобы защитить соединения, авторы могут включать строку комментариев (начинающуюся с символа «:») каждые 15 секунд или около того.
  • Авторы, желающие связать соединения источника событий друг с другом или с определенными ранее документами, могут обнаружить, что использование IP-адресов не работает. Отдельные клиенты могут иметь несколько IP-адресов (из-за наличия нескольких прокси-серверов) и отдельные IP-адреса могут иметь несколько клиентов (из-за совместного использования прокси-сервера). Лучше включать в документ уникальный идентификатор и передавать его как часть URL-адреса при установлении соединения.
  • Использование chunked transfer encoding может уменьшить надежность HTTP протокола, если блокирование выполняется другим слоем, не подозревающим о требованиях к синхронизации. Если эта проблема возникнет, блокирование может быть отключено для обслуживания потоков событий.
  • Клиенты, которые поддерживают ограничение на подключение к серверу через протокол HTTP, могут столкнуться с трудностями при открытии нескольких страниц сайта, если на каждой из этих страниц есть источник событий, расположенный в том же домене. Можно избежать этого, применяя механизм уникальных доменных имен для каждого соединения и разрешая пользователям включать функции EventSource для каждой страницы.
  • Поддержка браузера и полифиллы: Microsoft Edge не поддерживает эту реализацию. Но существует полифиллы, которые позволяют решить данную проблему. Тем не менее, самый важный сегмент для SSE — это мобильные устройства, где браузеры IE / Edge распространены незначительно.

Некоторые из доступных полифиллов:

· Yaffle.

· amvtek.

· remy.

Бесплатное подключение и другие функции

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

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

  1. Браузер подключается к удаленному HTTP-серверу и запрашивает ресурс, указанный автором в конструкторе EventSource.
  2. Сервер отправляет случайные сообщения.
  3. В промежутке между двумя сообщениями браузер обнаруживает, что он неактивен, за исключением активности сети, связанной с поддержанием TCP- соединения, и решает переключиться в спящий режим для экономии энергии.
  4. Браузер отключается от сервера.
  5. Браузер связывается с сервисом в сети и просит, чтобы служба «push proxy» поддерживала соединение.
  6. Служба «push proxy» связывается с удаленным HTTP-сервером и запрашивает ресурс, указанный в конструкторе EventSource (возможно, включая HTTP-заголовок последнего события и т. д.).
  7. Браузер позволяет мобильному устройству перейти в спящий режим.
  8. Сервер отправляет другое сообщение.
  9. Служба «push proxy» использует технологию OMA push для передачи события на мобильное устройство, которое выходит из спящего режима на время, достаточное для обработки события. Затем возвращается в спящий режим.

Подобный подход может снизить объем передаваемых данных и привести к значительной экономии энергии.

Помимо реализации существующего API и формата передаваемых данных ext/event-stream также могут поддерживаться форматы фреймворка событий, определенные другими спецификациями.

Что такое программирование серверной части сайта?

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

Запрос включает в себя URL, определяющий затронутый ресурс, метод, определяющий требуемое действие (например, получить, удалить или опубликовать ресурс) и может включать дополнительную информацию, закодированную в параметрах URL (пары поле-значение, оправленные как строка запроса), как POST запрос (данные, отправленные методом HTTP POST) или в куки-файлах.

Веб-серверы ожидают сообщений с клиентскими запросами, обрабатывают их по прибытию и отвечают веб-браузеру при помощи ответного HTTP сообщения (HTTP-ответ). Ответ содержит строку состояния, показывающую, был ли запрос успешным или нет (например, «HTTP/1.1 200 OK» в случае успеха).

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

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

Сервер извлекает запрошенный документ из своей файловой системы и возвращает HTTP-ответ, содержащий документ и (обычно 200 OK). Если файл не может быть извлечён по каким-либо причинам, возвращается статус ошибки (смотри и ).

Копирование числовых ячеек из 1С в Excel Промо

Решение проблемы, когда значения скопированных ячеек из табличных документов 1С в Excel воспринимаются последним как текст, т.е. без дополнительного форматирования значений невозможно применить арифметические операции. Поводом для публикации послужило понимание того, что целое предприятие с более сотней активных пользователей уже на протяжении года мучилось с такой, казалось бы на первый взгляд, тривиальной проблемой. Варианты решения, предложенные специалистами helpdesk, обслуживающими данное предприятие, а так же многочисленные обсуждения на форумах, только подтвердили убеждение в необходимости описания способа, который позволил мне качественно и быстро справиться с ситуацией.

Получите клиент удаленного рабочего стола и начинайте его использовать

В этом разделе вы узнаете, как скачать и настроить клиент удаленного рабочего стола для iOS.

Загрузите клиент удаленного рабочего стола из iOS Store

Сначала необходимо скачать клиент и настроить компьютер для подключения к удаленным ресурсам.

Чтобы скачать клиент, выполните следующие действия:

  1. Скачайте клиент Удаленного рабочего стола (Майкрософт) из iOS App Store или iTunes.
  2. .

Добавление компьютера

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

Чтобы добавить компьютер:

  1. В Центре подключений коснитесь + , а затем — +.
  2. Введите следующие сведения:
    • Имя компьютера — это имя компьютера. Это может быть имя компьютера с Windows, доменное имя в Интернете или IP-адрес. Вы также можете добавить сведения о порте к имени компьютера (например, MyDesktop:3389 или 10.0.0.1:3389).
    • Имя пользователя — это имя пользователя для доступа к удаленному компьютеру. Вы можете использовать следующие форматы: имя_пользователя, домен\имя_пользователя или . Кроме того, можно выбрать параметр Запрашивать при необходимости, чтобы имя пользователя и пароль запрашивались по необходимости.
  3. Можно также установить следующие дополнительные параметры:
    • Понятное имя (необязательно) — легко запоминаемое имя компьютера, к которому вы подключаетесь. Можно использовать любую строку, но если вы не укажете понятное имя, вместо него будет отображаться имя компьютера.
    • Шлюз (необязательно) — это шлюз удаленных рабочих столов, который вы хотите использовать для подключения к виртуальным рабочим столам, удаленным приложениям RemoteApp и рабочим столам на основе сеансов во внутренней корпоративной сети. Получите сведения о шлюзе от системного администратора.
    • Звук — выберите устройство, которое будет использоваться для воспроизведения аудио во время удаленного сеанса. Вы можете выбрать, воспроизводить ли звук на локальных устройствах, на удаленном устройстве или вообще не воспроизводить его.
    • Переключение кнопки мыши — всегда, когда жест мыши посылает команду левой кнопкой мыши, он посылает ту же команду и правой кнопкой мыши. Переключение кнопки мыши необходимо, если на удаленном компьютере настроен режим мыши для левши.
    • Режим администратора — подключитесь к сеансу администрирования на сервере, который работает на Windows Server 2003 или более поздней версии.
    • Буфер обмена — укажите, следует ли перенаправлять текст и изображения из буфера обмена на компьютер.
    • Хранилище — укажите, следует ли перенаправлять хранилище на компьютер.
  4. Выберите Сохранить.

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

Добавление рабочей области

Чтобы получить список управляемых ресурсов, к которым можно получить доступ в iOS, добавьте рабочую область, подписавшись на веб-канал, предоставленный администратором.

Чтобы добавить рабочую область:

  1. На экране Центра подключений коснитесь + , а затем — +.
  2. В поле «URL-адрес веб-канала» введите URL-адрес веб-канала, который нужно добавить. Можно указать URL-адрес или адрес электронной почты.
    • В первом случае используйте URL-адрес, предоставленный администратором.
      • Если обращение к ресурсам выполняется из Виртуального рабочего стола Azure или Windows 365, можно использовать один из следующих URL-адресов:
        • Если вы работаете с Виртуальным рабочим столом Azure (классический), используйте .
        • Если вы работаете с Виртуальным рабочим столом Azure, используйте .
        • Если вы работаете с Windows 365, используйте .
    • Во втором случае введите свой адрес электронной почты. При этом клиент будет искать URL-адрес, связанный с вашим адресом электронной почты, если администратор настроил сервер соответствующим образом.
  3. Коснитесь Next (Далее).
  4. При появлении запроса укажите учетные данные.
    • В поле Имя пользователя укажите имя пользователя учетной записи с разрешением на доступ к ресурсам.
    • В поле Пароль введите пароль для этой учетной записи.
    • Вам также может быть предложено ввести дополнительные сведения в зависимости от параметров, настроенных администратором для проверки подлинности.
  5. Выберите Сохранить.

Когда вы выполните эти действия, в Центре подключений должны отобразиться удаленные ресурсы.

Когда вы подпишетесь на веб-канал, его содержимое будет регулярно автоматически обновляться. Ресурсы могут добавляться, изменяться или удаляться в соответствии с изменениями, внесенными администратором.

(2)

Я ответил на некоторые подробности: https://stackoverflow.com/a/11045462/592477

Или вы можете прочитать его там ==>

Когда вы используете loadbalancing, это означает, что у вас есть несколько экземпляров tomcat, и вам нужно разделить нагрузки.

  • Если вы используете репликацию сеанса без липкого сеанса: представьте, что у вас есть только один пользователь, использующий ваше веб-приложение, и у вас есть 3 экземпляра tomcat. Этот пользователь отправляет несколько запросов в ваше приложение, тогда loadbalancer отправит некоторые из этих запросов в первый экземпляр tomcat и отправит некоторые другие из этих запросов во второй экземпляр, а другой — третьим.
  • Если вы используете липкую сессию без репликации: представьте, что у вас есть только один пользователь, использующий ваше веб-приложение, и у вас есть 3 экземпляра tomcat. Этот пользователь отправляет несколько запросов в ваше приложение, тогда loadbalancer отправит первый пользовательский запрос в один из трех экземпляров tomcat, а все остальные запросы, отправленные этим пользователем во время его сеанса, будут отправлены в тот же экземпляр tomcat. Во время этих запросов, если вы завершаете или перезапускаете этот экземпляр tomcat (экземпляр tomcat, который используется), loadbalancer отправляет оставшиеся запросы еще одному экземпляру tomcat, который все еще запущен, НО, поскольку вы не используете репликацию сеанса, экземпляр tomcat, который получает оставшиеся запросы не имеют копии сеанса пользователя, а затем для этого пользователя пользователь начинает сеанс: пользователь освобождает сессию и отключается от веб-приложения, хотя веб-приложение все еще работает.
  • Если вы используете липкую сессию С репликации сеанса: представьте, что у вас есть только один пользователь, использующий ваше веб-приложение, и у вас есть 3 экземпляра tomcat. Этот пользователь отправляет несколько запросов в ваше приложение, тогда loadbalancer отправит первый пользовательский запрос в один из трех экземпляров tomcat, а все остальные запросы, отправленные этим пользователем во время его сеанса, будут отправлены в тот же экземпляр tomcat. Во время этих запросов, если вы завершаете или перезапускаете этот экземпляр tomcat (экземпляр tomcat, который используется), loadbalancer отправляет оставшиеся запросы еще одному экземпляру tomcat, который все еще запущен, поскольку вы используете репликацию сеанса, экземпляр tomcat, который получает оставшиеся запросы, копия сеанса пользователя, а затем пользователь продолжает сеанс: пользователь продолжает просматривать веб-приложение без отключения, выключение экземпляра tomcat не влияет на навигацию пользователя.

Администрирование конфигураций 1С (недокументированные особенности работы)

Многие мои коллеги по работе и по профессии, уверен, сталкиваются с аналогичными ситуациями, когда программа 1С при работе с конфигурацией, мягко говоря, работает «странно». Как говорит один хороший знакомый (к слову, один из авторов УТ 11):
— «вот, ну согласись, нанять пару серьезных методистов — реальных дядечек с реального производства, до начала разработки — единственная ЭЛЕМЕНТАРНАЯ политика, как можно было этого не сделать???? там их НЕТ. Причем это 0 в плане затрат на разработку, там нет ограничений бюджета, это просто самый тупой прокол.»
В этой статье приведу способы лечения пресловутых проколов (за последний месяц).

Удаление неактивных и повторно запущенных пользователем сеансов — обработкой в фоне или внешней обработкой

На экране монитора при запуске конфигурации нередко приходится видеть обидное сообщение «Не обнаружено свободной лицензии». Особенно это актуально, когда у вас 100 лицензий и при этом работает порядка 90 пользователей. При этом, очень актуальна жесткая политика — «Один сеанс в одни руки». Для автоматизации ручной работы администратора 1С по удалению сеансов пользователей и предназначена данная обработка. Обработка может быть использована как внешняя, так и поставлена в дополнительные отчеты и обработки с установкой расписания запуска, в этом случае обработка будет выполняться как фоновое задание. Обработка предназначена для работы в клиент-серверных базах и тестировалась на платформе 8.3.14.1854. Обработка установленная на платформе не ниже 8.3.6, позволяет управлять сеансами конфигураций установленных на платформе 8.2

1 стартмани

Часто встречающиеся ошибки 1С и общие способы их решения Промо

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

Подведение итогов

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

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

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

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

  • Обзор: First steps
  • Далее
Рейтинг
( Пока оценок нет )
Понравилась статья? Поделиться с друзьями:
Все про сервера
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: