Форум программистов, компьютерный форум, киберфорум
C#: ASP.NET Core
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.60/5: Рейтинг темы: голосов - 5, средняя оценка - 4.60
 Аватар для firnen_dragon
25 / 25 / 4
Регистрация: 21.01.2019
Сообщений: 407

Связь между контейнерами Dockerfile

19.09.2024, 16:16. Показов 1649. Ответов 3

Студворк — интернет-сервис помощи студентам
Разбираюсь в том как работает микросервисная архитектура с применением Docker.
В общем сделал 2 проекта:
1.Сервис хэширования(просто возвращает хэш строки)
2.Web api связанное с бд
Каждый проект находится в своем контейнере.
В общем и цеолом по отдельности все работает свагер их видит, но когда я пытаюсь http клиентом запросить хэш в в проекте 1 из проекта 2 получаю следующую ошибку:
Кликните здесь для просмотра всего текста

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
System.Net.Http.HttpRequestException: Connection refused (localhost:8002)
 ---> System.Net.Sockets.SocketException (111): Connection refused
   at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
   at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token)
   at System.Net.Sockets.Socket.<ConnectAsync>g__WaitForConnectWithCancellation|285_0(AwaitableSocketAsyncEventArgs saea, ValueTask connectTask, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.AddHttp11ConnectionAsync(QueueItem queueItem)
   at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync(CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at Microsoft.Extensions.Http.Logging.LoggingHttpMessageHandler.<SendCoreAsync>g__Core|5_0(HttpRequestMessage request, Boolean useAsync, CancellationToken cancellationToken)
   at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.<SendCoreAsync>g__Core|5_0(HttpRequestMessage request, Boolean useAsync, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
   at WebApiDBTest.Controllers.WeatherForecastController.GetGetHash(String text) in C:\Users\Firnen\source\repos\DockerTest\WebApiDBTest\Controllers\WeatherForecastController.cs:line 40
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

Тем временем без котейнеров все работает хэш приходит куда надо, из чего делаю вывод, что я как-то неправильно связываю контейнеры
Запрашиваю хэш из проекта 2 я таким образом:
C#
1
2
3
4
5
6
7
[HttpGet("GetHash")]
public async Task<IActionResult> GetGetHash(string text)
{
    var response = await _httpClient.GetAsync($"https://localhost:8002/Hash?data={text}");
    _logger.LogInformation(response.ToString());
    return Ok(await response.Content.ReadAsStringAsync());
}
Dockerfile проектов:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app
EXPOSE 80
EXPOSE 443
 
 
# Этот этап используется для сборки проекта службы
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["HashService.csproj", "."]
RUN dotnet restore "./HashService.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "./HashService.csproj" -c $BUILD_CONFIGURATION -o /app/build
 
# Этот этап используется для публикации проекта службы, который будет скопирован на последний этап
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./HashService.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
 
# Этот этап используется в рабочей среде или при запуске из VS в обычном режиме (по умолчанию, когда конфигурация отладки не используется)
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "HashService.dll"]
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app
EXPOSE 80
EXPOSE 443
 
 
# Этот этап используется для сборки проекта службы
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["WebApiDBTest.csproj", "."]
RUN dotnet restore "./WebApiDBTest.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "./WebApiDBTest.csproj" -c $BUILD_CONFIGURATION -o /app/build
 
# Этот этап используется для публикации проекта службы, который будет скопирован на последний этап
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./WebApiDBTest.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
 
# Этот этап используется в рабочей среде или при запуске из VS в обычном режиме (по умолчанию, когда конфигурация отладки не используется)
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "WebApiDBTest.dll"]
launchSettings проектов и там и там одинаковый:
JSON
1
2
3
4
5
6
7
8
9
10
11
    "Container (Dockerfile)": {
      "commandName": "Docker",
      "launchBrowser": true,
      "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
      "environmentVariables": {
        "ASPNETCORE_HTTPS_PORTS": "8081",
        "ASPNETCORE_HTTP_PORTS": "8080"
      },
      "publishAllPorts": true,
      "useSSL": true
    }
docker-compose:
Code
1
2
3
4
5
6
7
8
9
10
11
services:
  webapidbtest:
    image: ${DOCKER_REGISTRY-}webapidbtest
    build:
      context: WebApiDBTest
      dockerfile: Dockerfile
  hashservice:
    image: ${DOCKER_REGISTRY-}hashservice
    build:
      context: HashService
      dockerfile: Dockerfile
docker-compose.override:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
services:
  webapidbtest:
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_HTTP_PORTS=8080
      - ASPNETCORE_HTTPS_PORTS=8081
    ports:
      - "8000:8081"
      - "8001:8080"
    volumes:
      - ${APPDATA}/Microsoft/UserSecrets:/home/app/.microsoft/usersecrets:ro
      - ${APPDATA}/ASP.NET/Https:/home/app/.aspnet/https:ro
  hashservice:
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_HTTP_PORTS=8080
      - ASPNETCORE_HTTPS_PORTS=8081
    ports:
      - "8002:8081"
      - "8003:8080"
    volumes:
      - ${APPDATA}/Microsoft/UserSecrets:/home/app/.microsoft/usersecrets:ro
      - ${APPDATA}/ASP.NET/Https:/home/app/.aspnet/https:ro
Подскажите пожалуйста где и когда я свернул не туда?

Не по теме:

когда решил поднять сервисы в отдельных докерах

0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
19.09.2024, 16:16
Ответы с готовыми решениями:

Связь между контейнерами
Добрый день! Подскажите пожалуйста, есть 2 контейнера: гитлаб и дженкинс. Чтобы один контейнер видел другой и наоборот в докере должна...

Сумма между двумя контейнерами
I need to create function Sum() that calculates sum between two containers. Code below work fine except function Sum between two...

Работа с контейнерами: данные обнуляются при взаимодействии форм между собой
есть клас: struct lab_6_14 { public string Name; public int Phone; public string Addres; ...

3
Эксперт .NET
 Аватар для Usaga
14087 / 9305 / 1348
Регистрация: 21.01.2016
Сообщений: 34,929
20.09.2024, 06:57
Лучший ответ Сообщение было отмечено firnen_dragon как решение

Решение

Цитата Сообщение от firnen_dragon Посмотреть сообщение
var response = await _httpClient.GetAsync($"https://localhost:8002/Hash?data={text}");
В данном случае LOCALHOST - это сам контейнер с WebAPI сервисом. И конечно же в этом контейнере на этом порту ничего нет. Вот ты и получаешь ошибку.

Надо использовать имя контейнра в виде хоста:

C#
1
var response = await _httpClient.GetAsync($"https://hashservice:8002/Hash?data={text}");
Это - первое.

Второе: паблишить порты не нужно. Сервисы внутри одной bridge-сети видят друг другая напрямую. Паблишить нужно только те порты, к которым нужен доступ извне.

Третье: использовать HTTPS для общения между сервисами внутри brigde-сети не нужно. Эта сеть изолированная и доверенная. Тоже касается и любых механизмов авторизации внутри сети.

Четвёртое: если извне нужен доступ по HTTPS, то для этого заводят ещё один сервис с reverse proxy (NGinx, HAProxy, Traefik) и на нём настраивают HTTPS, а так же certbot'а для обновления сертификатов.

Пятое: коли каждый контейнер представляет из себя отдельный "виртуальны" хост, то явно задавать порты для них не обязательно, они всё равно конфликтовать не будут. Поэтому задавать эти порты через переменные окружения на фиг не нужно. Можно во всех конейнерах использовать один и тот же порт.

Шестое: коли ты порты передаёшь через переменные окружения, то команды EXPOSE в Docker-файлах - полнейший мусор, который не соответствует действительности.

Седьмое: вот эти volumes в compose ты для какой цели шаришь между сервисами? Шоб було?
1
 Аватар для firnen_dragon
25 / 25 / 4
Регистрация: 21.01.2019
Сообщений: 407
07.10.2024, 15:57  [ТС]
Usaga, Боже наконец-то заработало, спасибо большое!

С паблиш портами почему-то не работало, убрал их из hashservice в композере, потом в httpClien так запросил:
C#
1
var response = await _httpClient.GetAsync($"http://hashservice:8080/Hash?data={text}");
Цитата Сообщение от Usaga Посмотреть сообщение
вот эти volumes в compose ты для какой цели шаришь между сервисами? Шоб було?
Я честно говоря без понятия для чего они нужны но если я их убираю, то у меня Run() в исключение выпадает

Добавлено через 5 часов 42 минуты
Usaga, Подскажите еще на счет подключения mysql, пытаюсь загрузить через композер, но все время получаю какую-то не очень понятную ошибку:
docker-compose:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
services:
  webapidbtest:
    image: ${DOCKER_REGISTRY-}webapidbtest
    build:
      context: WebApiDBTest
      dockerfile: Dockerfile
  hashservice:
    image: ${DOCKER_REGISTRY-}hashservice
    build:
      context: HashService
      dockerfile: Dockerfile
  database:
    image: mysql:8.0.22
    ports:
      - "3306:3306"
    volumes:
      - datafiles:/var/lib/mysql
      - "~/sql-scripts/setup.sql:/docker-entrypoint-initdb.d/1.sql"
    restart: always
    environment: 
      MYSQL_ROOT_PASSWORD: Root0++
      MYSQL_USER: newuser
      MYSQL_PASSWORD: pass@word1234
      MYSQL_DATABASE: Usersdb
Ошибка:
Кликните здесь для просмотра всего текста

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Ошибка (активно)   MSB4018 непредвиденная ошибка при выполнении задачи "GetServiceReferences".
System.IO.FileNotFoundException: Не удалось загрузить файл или сборку "Microsoft.Win32.Registry, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" либо одну из их зависимостей. Не удается найти указанный файл.
Имя файла: 'Microsoft.Win32.Registry, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
   в Microsoft.VisualStudio.Containers.Tools.Common.Client.DockerPathHelper.FindDockerCliPath()
   в Microsoft.VisualStudio.Containers.Tools.Common.Prerequisites.DockerForWindowsDriveSharingPrerequisite.<EvaluateAsync>d__0.MoveNext()
--- Конец трассировка стека из предыдущего расположения, где возникло исключение ---
   в System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   в System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   в Microsoft.Docker.Prerequisites.DockerForWindowsDriveSharingPrerequisite.<EvaluateAsync>d__3.MoveNext()
--- Конец трассировка стека из предыдущего расположения, где возникло исключение ---
   в System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   в Microsoft.Docker.Prerequisites.DockerCompositePrerequisite.<EvaluateAsync>d__3.MoveNext()
--- Конец трассировка стека из предыдущего расположения, где возникло исключение ---
   в System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   в System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   в Microsoft.Docker.BuildTasks.DockerBuildTask.<EvaluateBuildPrerequisitesAsync>d__39.MoveNext()
--- Конец трассировка стека из предыдущего расположения, где возникло исключение ---
   в System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   в System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   в Microsoft.Docker.BuildTasks.DockerBuildTask.<ExecuteAsync>d__38.MoveNext()
--- Конец трассировка стека из предыдущего расположения, где возникло исключение ---
   в System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   в System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   в Microsoft.Docker.BuildTasks.DockerBuildTask.Execute()
   в Microsoft.Build.BackEnd.TaskExecutionHost.Execute()
   в Microsoft.Build.BackEnd.TaskBuilder.<ExecuteInstantiatedTask>d__26.MoveNext()
 
Предупреждение: регистрация привязки сборок выключена.
Чтобы включить регистрацию ошибок привязки сборок, установите значение параметра реестра [HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) в 1.
Примечание. Регистрация ошибок привязки сборок может привести к некоторому снижению производительности.
Чтобы отключить эту функцию, удалите параметр реестра [HKLM\Software\Microsoft\Fusion!EnableLog].
    docker-compose  D:\programms\Microsoft Visual Studio\2022\Community\MSBuild\Sdks\Microsoft.Docker.Sdk\build\Microsoft.VisualStudio.Docker.Compose.targets   200
0
Эксперт .NET
 Аватар для Usaga
14087 / 9305 / 1348
Регистрация: 21.01.2016
Сообщений: 34,929
08.10.2024, 02:29
firnen_dragon, mysql к этой ошибке отношения не имеет. Текст исключения же сам за себя говорит, что пошло не так: не удалось загрузить сборку для работы с реестром. Встаёт вопрос зачем тебе понадобилось работать с реестром. Твой сервис в контейнере к реестру ломиться собрался? Каким образом, если в контейнере линукс и никаким реестром там даже близко не пахнет?
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
08.10.2024, 02:29
Помогаю со студенческими работами здесь

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

Найти связь между током в кабеле I(x) и разностью потенциалов phi(x) между жилой кабеля и землей
Подземный кабель имеет постоянное сопротивление r на единицу длины. Изоляция кабеля несовершенна и через нее происходит утечка....

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

Проблема с запуском Dockerfile
Суть проблемы вот в чем, после успешного создания контейнера я попытался запустить его: docker run --name test12-try test1:1.1.8 ...

Dockerfile добавить memcache
Кто силён в этом чёт мне неполучает нормально скомпилить dockerfile добавив php5-memcached может помочь это правильно сделать.. и ещё...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
4
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru