Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6345c30e06 | |||
| 2089284c26 | |||
| def391aba9 | |||
| 9bd815aa7e | |||
| 3245ffa10f | |||
| 9312ec1f2d | |||
| 6016907554 | |||
| cb14beb558 | |||
| e79202c319 | |||
| 6a49a5ea45 |
5
lab2/.gitignore
vendored
Normal file
5
lab2/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
**/*
|
||||||
|
!.gitignore
|
||||||
|
!report.tex
|
||||||
|
!img
|
||||||
|
!img/**
|
||||||
483
lab2/report.tex
Normal file
483
lab2/report.tex
Normal file
@@ -0,0 +1,483 @@
|
|||||||
|
\documentclass[a4paper, final]{article}
|
||||||
|
%\usepackage{literat} % Нормальные шрифты
|
||||||
|
\usepackage[14pt]{extsizes} % для того чтобы задать нестандартный 14-ый размер шрифта
|
||||||
|
\usepackage{tabularx}
|
||||||
|
\usepackage[T2A]{fontenc}
|
||||||
|
\usepackage[utf8]{inputenc}
|
||||||
|
\usepackage[russian]{babel}
|
||||||
|
\usepackage{amsmath}
|
||||||
|
\usepackage[left=25mm, top=20mm, right=20mm, bottom=20mm, footskip=10mm]{geometry}
|
||||||
|
\usepackage{ragged2e} %для растягивания по ширине
|
||||||
|
\usepackage{setspace} %для межстрочно го интервала
|
||||||
|
\usepackage{moreverb} %для работы с листингами
|
||||||
|
\usepackage{indentfirst} % для абзацного отступа
|
||||||
|
\usepackage{moreverb} %для печати в листинге исходного кода программ
|
||||||
|
\usepackage{pdfpages} %для вставки других pdf файлов
|
||||||
|
\usepackage{tikz}
|
||||||
|
\usepackage{graphicx}
|
||||||
|
\usepackage{afterpage}
|
||||||
|
\usepackage{longtable}
|
||||||
|
\usepackage{float}
|
||||||
|
\usepackage{tabularx}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
% \usepackage[paper=A4,DIV=12]{typearea}
|
||||||
|
\usepackage{pdflscape}
|
||||||
|
% \usepackage{lscape}
|
||||||
|
|
||||||
|
\usepackage{array}
|
||||||
|
\usepackage{multirow}
|
||||||
|
|
||||||
|
\renewcommand\verbatimtabsize{4\relax}
|
||||||
|
\renewcommand\listingoffset{0.2em} %отступ от номеров строк в листинге
|
||||||
|
\renewcommand{\arraystretch}{1.4} % изменяю высоту строки в таблице
|
||||||
|
\usepackage[font=small, singlelinecheck=false, justification=centering, format=plain, labelsep=period]{caption} %для настройки заголовка таблицы
|
||||||
|
\usepackage{listings} %листинги
|
||||||
|
\usepackage{xcolor} % цвета
|
||||||
|
\usepackage{hyperref}% для гиперссылок
|
||||||
|
\usepackage{enumitem} %для перечислений
|
||||||
|
|
||||||
|
\newcommand{\specialcell}[2][l]{\begin{tabular}[#1]{@{}l@{}}#2\end{tabular}}
|
||||||
|
|
||||||
|
|
||||||
|
\setlist[enumerate,itemize]{leftmargin=1.2cm} %отступ в перечислениях
|
||||||
|
|
||||||
|
\hypersetup{colorlinks,
|
||||||
|
allcolors=[RGB]{010 090 200}} %красивые гиперссылки (не красные)
|
||||||
|
|
||||||
|
% подгружаемые языки — подробнее в документации listings (это всё для листингов)
|
||||||
|
\lstloadlanguages{ SQL}
|
||||||
|
% включаем кириллицу и добавляем кое−какие опции
|
||||||
|
\lstset{tabsize=2,
|
||||||
|
breaklines,
|
||||||
|
basicstyle=\footnotesize,
|
||||||
|
columns=fullflexible,
|
||||||
|
flexiblecolumns,
|
||||||
|
numbers=left,
|
||||||
|
numberstyle={\footnotesize},
|
||||||
|
keywordstyle=\color{blue},
|
||||||
|
inputencoding=cp1251,
|
||||||
|
extendedchars=true
|
||||||
|
}
|
||||||
|
\lstdefinelanguage{MyC}{
|
||||||
|
language=SQL,
|
||||||
|
% ndkeywordstyle=\color{darkgray}\bfseries,
|
||||||
|
% identifierstyle=\color{black},
|
||||||
|
% morecomment=[n]{/**}{*/},
|
||||||
|
% commentstyle=\color{blue}\ttfamily,
|
||||||
|
% stringstyle=\color{red}\ttfamily,
|
||||||
|
% morestring=[b]",
|
||||||
|
% showstringspaces=false,
|
||||||
|
% morecomment=[l][\color{gray}]{//},
|
||||||
|
keepspaces=true,
|
||||||
|
escapechar=\%,
|
||||||
|
texcl=true
|
||||||
|
}
|
||||||
|
|
||||||
|
\textheight=24cm % высота текста
|
||||||
|
\textwidth=16cm % ширина текста
|
||||||
|
\oddsidemargin=0pt % отступ от левого края
|
||||||
|
\topmargin=-1.5cm % отступ от верхнего края
|
||||||
|
\parindent=24pt % абзацный отступ
|
||||||
|
\parskip=5pt % интервал между абзацами
|
||||||
|
\tolerance=2000 % терпимость к "жидким" строкам
|
||||||
|
\flushbottom % выравнивание высоты страниц
|
||||||
|
|
||||||
|
|
||||||
|
% Настройка листингов
|
||||||
|
\lstset{
|
||||||
|
language=C++,
|
||||||
|
extendedchars=\true,
|
||||||
|
inputencoding=utf8,
|
||||||
|
keepspaces=true,
|
||||||
|
% captionpos=b, % подписи листингов снизу
|
||||||
|
}
|
||||||
|
|
||||||
|
\begin{document} % начало документа
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
% НАЧАЛО ТИТУЛЬНОГО ЛИСТА
|
||||||
|
\begin{center}
|
||||||
|
\hfill \break
|
||||||
|
\hfill \break
|
||||||
|
\normalsize{МИНИСТЕРСТВО НАУКИ И ВЫСШЕГО ОБРАЗОВАНИЯ РОССИЙСКОЙ ФЕДЕРАЦИИ\\
|
||||||
|
федеральное государственное автономное образовательное учреждение высшего образования «Санкт-Петербургский политехнический университет Петра Великого»\\[10pt]}
|
||||||
|
\normalsize{Институт компьютерных наук и кибербезопасности}\\[10pt]
|
||||||
|
\normalsize{Высшая школа технологий искусственного интеллекта}\\[10pt]
|
||||||
|
\normalsize{Направление: 02.03.01 <<Математика и компьютерные науки>>}\\
|
||||||
|
|
||||||
|
\hfill \break
|
||||||
|
\hfill \break
|
||||||
|
\hfill \break
|
||||||
|
\hfill \break
|
||||||
|
\large{Лабораторная работа №2}\\
|
||||||
|
\large{<<Анализ пакетного трафика>>}\\
|
||||||
|
\large{по дисциплине <<Сети ЭВМ и телекоммуникации компьютерных сетей>>}\\
|
||||||
|
\hfill \break
|
||||||
|
|
||||||
|
% \hfill \break
|
||||||
|
\hfill \break
|
||||||
|
\end{center}
|
||||||
|
|
||||||
|
\small{
|
||||||
|
\begin{tabular}{lrrl}
|
||||||
|
\!\!\!Студент, & \hspace{2cm} & & \\
|
||||||
|
\!\!\!группы 5130201/20102 & \hspace{2cm} & \underline{\hspace{3cm}} &Тищенко А. А. \\\\
|
||||||
|
\!\!\!Преподаватель & \hspace{2cm} & \underline{\hspace{3cm}} & Мулюха В. А. \\\\
|
||||||
|
&&\hspace{4cm}
|
||||||
|
\end{tabular}
|
||||||
|
\begin{flushright}
|
||||||
|
<<\underline{\hspace{1cm}}>>\underline{\hspace{2.5cm}} 2025г.
|
||||||
|
\end{flushright}
|
||||||
|
}
|
||||||
|
|
||||||
|
\hfill \break
|
||||||
|
% \hfill \break
|
||||||
|
\begin{center} \small{Санкт-Петербург, 2025} \end{center}
|
||||||
|
\thispagestyle{empty} % выключаем отображение номера для этой страницы
|
||||||
|
|
||||||
|
% КОНЕЦ ТИТУЛЬНОГО ЛИСТА
|
||||||
|
% \newpage
|
||||||
|
% \tableofcontents
|
||||||
|
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Постановка задачи}
|
||||||
|
Необходимо установить и запустить программу tcpdump (с соответствующими библиотеками). tcpdump лучше запускать с опциями -XX -s 128 -S -e. Вывод tcpdump можно перенаправить в файл.
|
||||||
|
|
||||||
|
Не останавливая tcpdump выполнить последовательно:
|
||||||
|
\begin{enumerate}
|
||||||
|
\item Команду ping того адреса, который написан;
|
||||||
|
\item Команду traceroute (или tracert) того адреса, который указан;
|
||||||
|
\item Войти через браузер на третий адрес.
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
Остановить tcpdump.
|
||||||
|
|
||||||
|
В отчёте привести трафик соответствующий проводимым действиям и уметь ответить на вопросы какая строчка вывода соответствует какому действию и что вообще делает. Где какое поле и т.п.
|
||||||
|
|
||||||
|
Если между действиями в tcpdump попал другой трафик, то часть вывода можно сократить, приведя только нужный.
|
||||||
|
|
||||||
|
\begin{table}[h!]
|
||||||
|
\centering
|
||||||
|
% \caption{.}
|
||||||
|
\footnotesize
|
||||||
|
\begin{tabularx}{\textwidth}{|X|X|X|X|}
|
||||||
|
\hline
|
||||||
|
\textbf{Вариант} & \textbf{ping} & \textbf{tracert} & \textbf{web-доступ} \\
|
||||||
|
\hline
|
||||||
|
34 & myblog.jp & blogg.de & mega.cl \\
|
||||||
|
\hline
|
||||||
|
\end{tabularx}
|
||||||
|
\end{table}
|
||||||
|
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Ход работы}
|
||||||
|
\subsection{Подготовка}
|
||||||
|
Вместо tcpdump был установлен его полный аналог для ОС Windows -- WinDump (\url{https://www.winpcap.org/windump/install/}), в связке с библиотекой WinPcap. Исполняемый файл \texttt{WinDump.exe} был добавлен в PATH.
|
||||||
|
|
||||||
|
С помощью команды \texttt{windump -D}, которая выводит список сетевых интерфейсов и их номеров, был определён номер основного сетевого интерфейса, используемого ноутбуком. В частности это оказался интерфейс под номером 2, поэтому далее в работе в параметре \texttt{-i} будет указан именно он.
|
||||||
|
|
||||||
|
\subsection{Команда ping}
|
||||||
|
|
||||||
|
Открываем два окна консоли. В одном выполняем команду \texttt{windump -XX -s 128 -S -e -i 2 icmp}, с помощью которой будем отлавливать icmp пакеты. В другом выполняем команду \texttt{ping myblog.jp}. Выводы команд представлены в листингах~\ref{lst:ping}~и~\ref{lst:ping-windump}.
|
||||||
|
|
||||||
|
\begin{lstlisting}[caption={Вывод команды \texttt{ping myblog.jp}.}, label={lst:ping}]
|
||||||
|
Обмен пакетами с myblog.jp [163.43.102.56] с 32 байтами данных:
|
||||||
|
Ответ от 163.43.102.56: число байт=32 время=206мс TTL=40
|
||||||
|
Ответ от 163.43.102.56: число байт=32 время=204мс TTL=40
|
||||||
|
Ответ от 163.43.102.56: число байт=32 время=212мс TTL=40
|
||||||
|
Ответ от 163.43.102.56: число байт=32 время=210мс TTL=40
|
||||||
|
|
||||||
|
Статистика Ping для 163.43.102.56:
|
||||||
|
Пакетов: отправлено = 4, получено = 4, потеряно = 0
|
||||||
|
(0% потерь)
|
||||||
|
Приблизительное время приема-передачи в мс:
|
||||||
|
Минимальное = 204мсек, Максимальное = 212 мсек, Среднее = 208 мсек\end{lstlisting}
|
||||||
|
|
||||||
|
\begin{lstlisting}[caption={windump -XX -s 128 -S -e -i 2 icmp.}, label={lst:ping-windump}]
|
||||||
|
windump: listening on \Device\NPF_{7B52B01B-3CC8-4A94-A3C3-E6EC1A52EE5B}
|
||||||
|
21:22:48.160122 7a:12:0e:01:fd:36 (oui Unknown) > ce:24:0b:a1:a4:fb (oui Unknown), ethertype IPv4 (0x0800), length 74: artem > www3846.sakura.ne.jp: ICMP echo request, id 1, seq 62, length 40
|
||||||
|
0x0000: ce24 0ba1 a4fb 7a12 0e01 fd36 0800 4500 .$....z....6..E.
|
||||||
|
0x0010: 003c 1cff 0000 8001 1b8a c0a8 382c a32b .<..........8,.+
|
||||||
|
0x0020: 6638 0800 4d1d 0001 003e 6162 6364 6566 f8..M....>abcdef
|
||||||
|
0x0030: 6768 696a 6b6c 6d6e 6f70 7172 7374 7576 ghijklmnopqrstuv
|
||||||
|
0x0040: 7761 6263 6465 6667 6869 wabcdefghi
|
||||||
|
21:22:48.366759 ce:24:0b:a1:a4:fb (oui Unknown) > 7a:12:0e:01:fd:36 (oui Unknown), ethertype IPv4 (0x0800), length 74: www3846.sakura.ne.jp > artem: ICMP echo reply, id 1, seq 62, length 40
|
||||||
|
0x0000: 7a12 0e01 fd36 ce24 0ba1 a4fb 0800 4500 z....6.$......E.
|
||||||
|
0x0010: 003c 7341 0000 2801 1d48 a32b 6638 c0a8 .<sA..(..H.+f8..
|
||||||
|
0x0020: 382c 0000 551d 0001 003e 6162 6364 6566 8,..U....>abcdef
|
||||||
|
0x0030: 6768 696a 6b6c 6d6e 6f70 7172 7374 7576 ghijklmnopqrstuv
|
||||||
|
0x0040: 7761 6263 6465 6667 6869 wabcdefghi
|
||||||
|
21:22:49.171976 7a:12:0e:01:fd:36 (oui Unknown) > ce:24:0b:a1:a4:fb (oui Unknown), ethertype IPv4 (0x0800), length 74: artem > www3846.sakura.ne.jp: ICMP echo request, id 1, seq 63, length 40
|
||||||
|
0x0000: ce24 0ba1 a4fb 7a12 0e01 fd36 0800 4500 .$....z....6..E.
|
||||||
|
0x0010: 003c 1d00 0000 8001 1b89 c0a8 382c a32b .<..........8,.+
|
||||||
|
0x0020: 6638 0800 4d1c 0001 003f 6162 6364 6566 f8..M....?abcdef
|
||||||
|
0x0030: 6768 696a 6b6c 6d6e 6f70 7172 7374 7576 ghijklmnopqrstuv
|
||||||
|
0x0040: 7761 6263 6465 6667 6869 wabcdefghi
|
||||||
|
21:22:49.375868 ce:24:0b:a1:a4:fb (oui Unknown) > 7a:12:0e:01:fd:36 (oui Unknown), ethertype IPv4 (0x0800), length 74: www3846.sakura.ne.jp > artem: ICMP echo reply, id 1, seq 63, length 40
|
||||||
|
0x0000: 7a12 0e01 fd36 ce24 0ba1 a4fb 0800 4500 z....6.$......E.
|
||||||
|
0x0010: 003c 7343 0000 2801 1d46 a32b 6638 c0a8 .<sC..(..F.+f8..
|
||||||
|
0x0020: 382c 0000 551c 0001 003f 6162 6364 6566 8,..U....?abcdef
|
||||||
|
0x0030: 6768 696a 6b6c 6d6e 6f70 7172 7374 7576 ghijklmnopqrstuv
|
||||||
|
0x0040: 7761 6263 6465 6667 6869 wabcdefghi
|
||||||
|
21:22:50.182542 7a:12:0e:01:fd:36 (oui Unknown) > ce:24:0b:a1:a4:fb (oui Unknown), ethertype IPv4 (0x0800), length 74: artem > www3846.sakura.ne.jp: ICMP echo request, id 1, seq 64, length 40
|
||||||
|
0x0000: ce24 0ba1 a4fb 7a12 0e01 fd36 0800 4500 .$....z....6..E.
|
||||||
|
0x0010: 003c 1d01 0000 8001 1b88 c0a8 382c a32b .<..........8,.+
|
||||||
|
0x0020: 6638 0800 4d1b 0001 0040 6162 6364 6566 f8..M....@abcdef
|
||||||
|
0x0030: 6768 696a 6b6c 6d6e 6f70 7172 7374 7576 ghijklmnopqrstuv
|
||||||
|
0x0040: 7761 6263 6465 6667 6869 wabcdefghi
|
||||||
|
21:22:50.394953 ce:24:0b:a1:a4:fb (oui Unknown) > 7a:12:0e:01:fd:36 (oui Unknown), ethertype IPv4 (0x0800), length 74: www3846.sakura.ne.jp > artem: ICMP echo reply, id 1, seq 64, length 40
|
||||||
|
0x0000: 7a12 0e01 fd36 ce24 0ba1 a4fb 0800 4500 z....6.$......E.
|
||||||
|
0x0010: 003c 7345 0000 2801 1d44 a32b 6638 c0a8 .<sE..(..D.+f8..
|
||||||
|
0x0020: 382c 0000 551b 0001 0040 6162 6364 6566 8,..U....@abcdef
|
||||||
|
0x0030: 6768 696a 6b6c 6d6e 6f70 7172 7374 7576 ghijklmnopqrstuv
|
||||||
|
0x0040: 7761 6263 6465 6667 6869 wabcdefghi
|
||||||
|
21:22:51.194625 7a:12:0e:01:fd:36 (oui Unknown) > ce:24:0b:a1:a4:fb (oui Unknown), ethertype IPv4 (0x0800), length 74: artem > www3846.sakura.ne.jp: ICMP echo request, id 1, seq 65, length 40
|
||||||
|
0x0000: ce24 0ba1 a4fb 7a12 0e01 fd36 0800 4500 .$....z....6..E.
|
||||||
|
0x0010: 003c 1d02 0000 8001 1b87 c0a8 382c a32b .<..........8,.+
|
||||||
|
0x0020: 6638 0800 4d1a 0001 0041 6162 6364 6566 f8..M....Aabcdef
|
||||||
|
0x0030: 6768 696a 6b6c 6d6e 6f70 7172 7374 7576 ghijklmnopqrstuv
|
||||||
|
0x0040: 7761 6263 6465 6667 6869 wabcdefghi
|
||||||
|
21:22:51.404994 ce:24:0b:a1:a4:fb (oui Unknown) > 7a:12:0e:01:fd:36 (oui Unknown), ethertype IPv4 (0x0800), length 74: www3846.sakura.ne.jp > artem: ICMP echo reply, id 1, seq 65, length 40
|
||||||
|
0x0000: 7a12 0e01 fd36 ce24 0ba1 a4fb 0800 4500 z....6.$......E.
|
||||||
|
0x0010: 003c 7348 0000 2801 1d41 a32b 6638 c0a8 .<sH..(..A.+f8..
|
||||||
|
0x0020: 382c 0000 551a 0001 0041 6162 6364 6566 8,..U....Aabcdef
|
||||||
|
0x0030: 6768 696a 6b6c 6d6e 6f70 7172 7374 7576 ghijklmnopqrstuv
|
||||||
|
0x0040: 7761 6263 6465 6667 6869 wabcdefghi
|
||||||
|
|
||||||
|
8 packets captured
|
||||||
|
69 packets received by filter
|
||||||
|
0 packets dropped by kernel\end{lstlisting}
|
||||||
|
|
||||||
|
В выводе команды windump (листинг~\ref{lst:ping-windump}) представлена информация о восьми пакетах. Разберём первый из них (строки 2-7).
|
||||||
|
|
||||||
|
В строке 2 указана следующая информация о пакете:
|
||||||
|
\begin{enumerate}
|
||||||
|
\item \texttt{21:22:48.160122} -- время, когда пакет был захвачен (чч:мм:сс.мс);
|
||||||
|
\item \texttt{7a:12:0e:01:fd:36 (oui Unknown)} -- MAC-адрес отправителя (отправляющий хост), OUI -- Organizationally Unique Identifier -- код производителя устройства, в данном случае производителя по коду (первые три байта -- \texttt{7a:12:0e}) определить не удалось;
|
||||||
|
\item \texttt{ce:24:0b:a1:a4:fb (oui Unknown)} -- MAC-адрес получателя (маршрутизатор или шлюз);
|
||||||
|
\item \texttt{ethertype IPv4 (0x0800)} -- кадр содержит IPv4-пакет;
|
||||||
|
\item \texttt{length 74} -- длина Ethernet-кадра 74 байта;
|
||||||
|
\item \texttt{artem > www3846.sakura.ne.jp} -- IPадрес отправителя (artem) и адрес получателя (www3846.sakura.ne.jp);
|
||||||
|
\item \texttt{ICMP echo request, id 1, seq 62, length 40} -- содержит информацию об ICMP (Internet Control Message Protocol) запросе. \texttt{echo request} означает, что это запрос, а не ответ на ping (\texttt{echo reply}).
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
В строках 3-7 идёт непосредственно дамп пакета. По нему видно, что были переданы следующие байты:
|
||||||
|
|
||||||
|
\begin{enumerate}
|
||||||
|
\item \texttt{ce24 0ba1 a4fb 7a12 0e01 fd36 0800} -- первые 14 байт это заголовок Ethernet-кадра.
|
||||||
|
\begin{itemize}
|
||||||
|
\item \texttt{ce24 0ba1 a4fb} — MAC-адрес получателя.
|
||||||
|
\item \texttt{7a12 0e01 fd36} — MAC-адрес отправителя.
|
||||||
|
\item \texttt{0800} — Тип пакета, который завёрнут в Ethernet.\texttt{0800} — это тип протокола, который указывает, что данные в кадре Ethernet содержат пакет IPv4 (Internet Protocol version 4).
|
||||||
|
Другие возможные типы:
|
||||||
|
\begin{itemize}
|
||||||
|
\item \texttt{86DD} — IPv6.
|
||||||
|
\item \texttt{0806} — ARP (Address Resolution Protocol).
|
||||||
|
\item \texttt{8847} — MPLS (Multi-Protocol Label Switching).
|
||||||
|
\item \texttt{8848} — MPLS Multicast.
|
||||||
|
\item И другие.
|
||||||
|
\end{itemize}
|
||||||
|
\end{itemize}
|
||||||
|
\item \texttt{4500 003c 1cff 0000 8001 1b8a c0a8 382c a32b 6638} -- следующие 20 байт это заголовок IPv4.
|
||||||
|
\begin{itemize}
|
||||||
|
\item \texttt{45} — первый байт: версия и длина заголовка.
|
||||||
|
\begin{itemize}
|
||||||
|
\item Первая цифра \texttt{4} — это версия протокола, что означает \texttt{IPv4}.
|
||||||
|
\item Вторая цифра \texttt{5} — это длина заголовка в 32-битных словах, где \texttt{5} означает 5 слов, то есть 5 × 4 = 20 байт (стандартная длина IPv4-заголовка).
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\item \texttt{003c} — значение указывает на общий размер пакета (заголовок + данные), равный 60 байт.
|
||||||
|
|
||||||
|
\item \texttt{1cff} — идентификатор пакета.
|
||||||
|
\begin{itemize}
|
||||||
|
\item Это поле используется для фрагментации пакета. Идентификатор \texttt{1cff} уникален для каждого фрагмента одного пакета, чтобы при получении фрагменты могли быть правильно собраны.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\item \texttt{0000} — флаги и смещение фрагмента.
|
||||||
|
\begin{itemize}
|
||||||
|
\item Первая часть \texttt{0000} указывает на то, что фрагментация не используется (все биты флагов равны 0).
|
||||||
|
\item Сдвиг фрагмента также равен 0.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\item \texttt{80} — TTL (Time to Live).
|
||||||
|
\begin{itemize}
|
||||||
|
\item \texttt{80} в шестнадцатеричной системе равно \texttt{128} в десятичной системе.
|
||||||
|
\item Это значение определяет максимальное количество маршрутизаторов (хопов), через которые может пройти пакет, прежде чем он будет отброшен.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\item \texttt{01} — протокол данных внутри IPv4. \texttt{01} указывает на протокол ICMP (Internet Control Message Protocol).
|
||||||
|
|
||||||
|
\begin{itemize}
|
||||||
|
\item \texttt{01} — ICMP (Internet Control Message Protocol): используется для обмена сообщениями контроля и диагностики, например, команда \texttt{ping}.
|
||||||
|
\item \texttt{06} — TCP (Transmission Control Protocol).
|
||||||
|
\item \texttt{11} — UDP (User Datagram Protocol).
|
||||||
|
\item и некоторые другие.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\item \texttt{1b8a} — контрольная сумма заголовка.
|
||||||
|
\begin{itemize}
|
||||||
|
\item Это значение используется для проверки целостности заголовка IPv4. Контрольная сумма пересчитывается на каждом маршрутизаторе.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\item \texttt{c0a8 382c} — IP-адрес источника.
|
||||||
|
\begin{itemize}
|
||||||
|
\item \texttt{c0a8 382c} в шестнадцатеричной системе соответствует IP-адресу \texttt{192.168.56.44}.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\item \texttt{a32b 6638} — IP-адрес назначения.
|
||||||
|
\begin{itemize}
|
||||||
|
\item \texttt{a32b 6638} в шестнадцатеричной системе соответствует IP-адресу \texttt{163.43.102.56}.
|
||||||
|
\end{itemize}
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
|
||||||
|
\item \texttt{0800 4d1d 0001 003e} -- заголовок ICMP (8 байт).
|
||||||
|
\begin{itemize}
|
||||||
|
\item \texttt{08} — Тип ICMP сообщения.
|
||||||
|
\begin{itemize}
|
||||||
|
\item \texttt{08} указывает на тип сообщения ICMP: Echo Request (запрос эхо), используемый в команде \texttt{ping}.
|
||||||
|
\item \texttt{00} -- Echo Reply.
|
||||||
|
\item есть и другие типы.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\item \texttt{00} — Код ICMP сообщения. Может содержать информацию о типе ошибки. Для нормальных Echo Request и Echo Reply код 0 означает, что всё штатно.
|
||||||
|
|
||||||
|
\item \texttt{4d1d} — Контрольная сумма заголовка и данных ICMP.
|
||||||
|
|
||||||
|
\item \texttt{0001} — Идентификатор запроса.
|
||||||
|
|
||||||
|
\item \texttt{003e} — Номер последовательности (62 в десятичной системе).
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\item \texttt{6162 6364 6566 6768 696a 6b6c 6d6e 6f70 7172 7374 7576 7761 6263 6465 6667 6869} -- данные внутри ICMP (32 байта). Просто буквы \texttt{abcdefghijklmnopq} \texttt{rstuvwabcdefghi}.
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
\subsection{Команда tracert}
|
||||||
|
|
||||||
|
\textbf{Команда \texttt{tracert}} (traceroute) — утилита для определения маршрута следования сетевых пакетов до указанного узла. Она:
|
||||||
|
\begin{itemize}
|
||||||
|
\item Отправляет серию ICMP-пакетов с увеличивающимся значением TTL (Time To Live).
|
||||||
|
\item Фиксирует ответы от промежуточных маршрутизаторов (хостов) и время задержки.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\begin{lstlisting}[caption={Вывод команды \texttt{tracert blogg.de}.}, label={lst:tracert}]
|
||||||
|
Трассировка маршрута к blogg.de [85.13.145.176] с максимальным числом прыжков 30:
|
||||||
|
|
||||||
|
1 <1 мс <1 мс <1 мс 192.168.56.20
|
||||||
|
2 * * * Превышен интервал ожидания для запроса.
|
||||||
|
3 24 ms 26 ms 39 ms 10.226.12.85
|
||||||
|
4 15 ms 28 ms 20 ms 10.226.8.85
|
||||||
|
5 34 ms 24 ms 31 ms 10.226.8.98
|
||||||
|
6 21 ms 18 ms 16 ms 10.226.7.90
|
||||||
|
7 * * * Превышен интервал ожидания для запроса.
|
||||||
|
8 18 ms 21 ms 15 ms spb-ivc-cr2.ae2544-0.rascom.as20764.net [80.64.108.138]
|
||||||
|
9 * * * Превышен интервал ожидания для запроса.
|
||||||
|
10 57 ms 58 ms 57 ms 80.81.192.39
|
||||||
|
11 62 ms 62 ms 78 ms dd26736.kasserver.com [85.13.145.176]
|
||||||
|
|
||||||
|
Трассировка завершена.\end{lstlisting}
|
||||||
|
|
||||||
|
\begin{itemize}
|
||||||
|
\item \textbf{1:} \texttt{<1 мс <1 мс <1 мс 192.168.56.20}
|
||||||
|
Это первый шаг трассировки. Ответ от локального маршрутизатора (IP-адрес \texttt{192.168.56.20}), с минимальным временем отклика (менее 1 мс). Это IP-адрес в локальной сети, который является шлюзом по умолчанию.
|
||||||
|
|
||||||
|
\item \textbf{2:} \texttt{* * * Превышен интервал ожидания для запроса.}
|
||||||
|
На втором шаге не было получено ответа. Это может означать, что маршрутизатор не отвечает на ICMP-запросы (ping).
|
||||||
|
|
||||||
|
\item \textbf{3-6:}
|
||||||
|
Ответы от промежуточных маршрутизаторов с IP-адресами \texttt{10.226.12.85}, \texttt{10.226.8.85}, \texttt{10.226.8.98}, \texttt{10.226.7.90}. Скорее всего это маршрутизаторы внутри сети провайдера.
|
||||||
|
|
||||||
|
\item \textbf{7:} \texttt{* * * Превышен интервал ожидания для запроса.}
|
||||||
|
На этом шаге опять нет ответа. Это может означать, что промежуточное оборудование не отвечает на ICMP-запросы.
|
||||||
|
|
||||||
|
\item \textbf{8:} \texttt{18 мс 21 мс 15 мс spb-ivc-cr2.ae2544-0.rascom.as20764.net}\\ \texttt{[80.64.108.138]}
|
||||||
|
Ответ от маршрутизатора \texttt{80.64.108.138} с именем \\ \texttt{spb-ivc-cr2.ae2544-0.rascom.as20764.net}. Узел из сети Санкт-Петербургского провайдера РАСКОМ (\url{https://ipinfo.io/ips/80.64.108.0/24}).
|
||||||
|
|
||||||
|
\item \textbf{10:} \texttt{57 мс 58 мс 57 мс 80.81.192.39}
|
||||||
|
Ответ от маршрутизатора с IP-адресом \texttt{80.81.192.39}. Время отклика от 57 мс до 58 мс. Этот IP адресс находится в сети немецкого провайдера \textit{Neue Medien Muennich GmbH}. Само устройство, связанное с этим IP адресом, находится в дата-центре \textit{DE-CIX} во Франкфурте. Данные с сайта \url{https://bgp.he.net/exchange/DE-CIX%20Frankfurt}.
|
||||||
|
|
||||||
|
\item \textbf{11:} \texttt{62 мс 62 мс 78 мс dd26736.kasserver.com [85.13.145.176]}
|
||||||
|
Ответ от целевого сервера \texttt{dd26736.kasserver.com} с IP-адресом \texttt{85.13.145.176}. Это последний маршрутизатор на пути, который принадлежит хостинг-платформе, на которой размещён сайт \texttt{blogg.de}. Время отклика варьируется от 62 мс до 78 мс.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
Паралелльно с выполнением \texttt{tracert} была запущена команда \texttt{windump -XX -s 128 -S -e -i 2 -v icmp}. За время выполнения команды \texttt{tracert} было поймано 90 пакетов. Первый запрос с ttl 1 и ответ на него представлен в листинге~\ref{lst:windump-tracert}. По нему видно, что ближайший маршрутизатор \texttt{192.168.56.20} вернул ICMP Time Exceeded. Также по выводу windump видно, что, в отличие от команды ping, tracert заполняет поле данных запроса нулями. В остальном это такой же ICMP Echo Request.
|
||||||
|
|
||||||
|
|
||||||
|
\begin{lstlisting}[caption={Вывод windump во время выполнения tracert.}, label={lst:windump-tracert}]
|
||||||
|
19:22:50.704303 96:48:79:96:d1:f6 (oui Unknown) > 8a:c4:3e:12:66:73 (oui Unknown), ethertype IPv4 (0x0800), length 106: (tos 0x0, ttl 1, id 50580, offset 0, flags [none], proto: ICMP (1), length: 92) artem > dd26736.kasserver.com: ICMP echo request, id 1, seq 148, length 72
|
||||||
|
0x0000: 8ac4 3e12 6673 9648 7996 d1f6 0800 4500 ..>.fs.Hy.....E.
|
||||||
|
0x0010: 005c c594 0000 0101 147b c0a8 382c 550d .\.......{..8,U.
|
||||||
|
0x0020: 91b0 0800 f76a 0001 0094 0000 0000 0000 .....j..........
|
||||||
|
0x0030: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
||||||
|
0x0040: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
||||||
|
0x0050: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
||||||
|
0x0060: 0000 0000 0000 0000 0000 ..........
|
||||||
|
19:22:50.704638 8a:c4:3e:12:66:73 (oui Unknown) > 96:48:79:96:d1:f6 (oui Unknown), ethertype IPv4 (0x0800), length 134: (tos 0xc0, ttl 64, id 36552, offset 0, flags [none], proto: ICMP (1), length: 120) 192.168.56.20 > artem: ICMP time exceeded in-transit, length 100
|
||||||
|
(tos 0x0, ttl 1, id 50580, offset 0, flags [none], proto: ICMP (1), length: 92) artem > dd26736.kasserver.com: ICMP echo request, id 1, seq 148, length 72
|
||||||
|
0x0000: 9648 7996 d1f6 8ac4 3e12 6673 0800 45c0 .Hy.....>.fs..E.
|
||||||
|
0x0010: 0078 8ec8 0000 4001 f96b c0a8 3814 c0a8 .x....@..k..8...
|
||||||
|
0x0020: 382c 0b00 f4ff 0000 0000 4500 005c c594 8,........E..\..
|
||||||
|
0x0030: 0000 0101 147b c0a8 382c 550d 91b0 0800 .....{..8,U.....
|
||||||
|
0x0040: f76a 0001 0094 0000 0000 0000 0000 0000 .j..............
|
||||||
|
0x0050: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
||||||
|
0x0060: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
||||||
|
0x0070: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
\subsection{Открытие сайта в браузер}
|
||||||
|
Для выполнения последней задачи необходимо было открыть сайт \url{mega.cl} в браузере с включённым windump, для запуска которого использовалась команда \texttt{windump -i 2 -v host mega.cl}.
|
||||||
|
|
||||||
|
Первые три пакета (листинг~\ref{lst:first-three}) используются для установки TCP соединения между клиентом и сервером.
|
||||||
|
|
||||||
|
\begin{lstlisting}[caption={Первые три пакета.}, label={lst:first-three}]
|
||||||
|
19:41:58.828210 IP (tos 0x0, ttl 128, id 20148, offset 0, flags [DF], proto: TCP (6), length: 52) artem.61628 > as5300-c4-139.cpc.entelchile.net.443: S, cksum 0xee91 (correct), 1029066177:1029066177(0) win 8760 <mss 1460,nop,wscale 8,nop,nop,sackOK>
|
||||||
|
19:41:59.074184 IP (tos 0x0, ttl 238, id 5828, offset 0, flags [DF], proto: TCP (6), length: 52) as5300-c4-139.cpc.entelchile.net.443 > artem.61628: S, cksum 0x889f (correct), 1631908201:1631908201(0) ack 1029066178 win 14000 <mss 1400,nop,wscale 0,sackOK,eol>
|
||||||
|
19:41:59.074345 IP (tos 0x0, ttl 128, id 20150, offset 0, flags [DF], proto: TCP (6), length: 40) artem.61628 > as5300-c4-139.cpc.entelchile.net.443: ., cksum 0xfebb (correct), ack 1 win 34
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
Рассмотрим каждый пакет по отдельности:
|
||||||
|
\begin{enumerate}
|
||||||
|
\item Клиент (ноутбук artem) с порта 61628 отправляет TCP-пакет (упакованный в IP пакет) с флагом S (SYN) для инициализации соединения с сервером as5300-c4-139.cpc.entelchile.net по порту 443 (HTTPS). Отправляется также номер последовательности -- 1029066177.
|
||||||
|
\item Сервер отвечает пакетом с флагом S (SYN) и ACK (windump не выводит его явно, но можно понять, что он передаётся по наличию поля ack). В поле ack сервер указывает 1029066178, то есть увеличенный на единицу номер последовательности, который передал клиент при установке соединения. Также сервер отправляет новый номер последовательности -- 1631908201.
|
||||||
|
\item Клиент отправляет пакет с флагом ACK (выводится как .), подтверждая получения SYN-ACK пакета.
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
После установки соединения начинается передача данных. В листинге~\ref{lst:request} видно, как клиент отправляет пакет с флагом P (PUSH) и передаёт 317 байт данных. Клиент указывает диапазон переданных байтов -- 1401:1718. За ним следует ответ от сервера с флагом ACK (.). В поле ack сервер указывает конец диапазона байтов, получение которых он подтверждает (ack 1718). Скорее всего в этом пакете клиент делает HTTP запрос.
|
||||||
|
|
||||||
|
\begin{lstlisting}[caption={Клиент делает запрос.}, label={lst:request}]
|
||||||
|
19:41:59.075165 IP (tos 0x0, ttl 128, id 20152, offset 0, flags [DF], proto: TCP (6), length: 357) artem.61628 > as5300-c4-139.cpc.entelchile.net.443: P 1401:1718(317) ack 1 win 34
|
||||||
|
19:41:59.336245 IP (tos 0x0, ttl 238, id 6571, offset 0, flags [DF], proto: TCP (6), length: 40) as5300-c4-139.cpc.entelchile.net.443 > artem.61628: ., cksum 0xbac3 (correct), ack 1718 win 15717
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
Затем сервер начинает передавать клиенту ответные данные (листинг~\ref{lst:response}). Клиент отвечает и подтверждает, что принял данные. Последний пакет сервер отправляет с флагом P (PUSH), чтобы клиент начал обработку пришёдших данных. На этот пакет клиент также отвечает подтверждением.
|
||||||
|
|
||||||
|
\begin{lstlisting}[caption={Сервер отвечает.}, label={lst:response}]
|
||||||
|
19:41:59.341484 IP (tos 0x0, ttl 238, id 6602, offset 0, flags [DF], proto: TCP (6), length: 206) as5300-c4-139.cpc.entelchile.net.443 > artem.61628: . 1:167(166) ack 1718 win 15717
|
||||||
|
19:41:59.341647 IP (tos 0x0, ttl 238, id 6603, offset 0, flags [DF], proto: TCP (6), length: 1440) as5300-c4-139.cpc.entelchile.net.443 > artem.61628: . 167:1567(1400) ack 1718 win 15717
|
||||||
|
19:41:59.341683 IP (tos 0x0, ttl 128, id 20154, offset 0, flags [DF], proto: TCP (6), length: 40) artem.61628 > as5300-c4-139.cpc.entelchile.net.443: ., cksum 0xf1e8 (correct), ack 1567 win 34
|
||||||
|
19:41:59.341727 IP (tos 0x0, ttl 238, id 6604, offset 0, flags [DF], proto: TCP (6), length: 1440) as5300-c4-139.cpc.entelchile.net.443 > artem.61628: . 1567:2967(1400) ack 1718 win 15717
|
||||||
|
19:41:59.341757 IP (tos 0x0, ttl 238, id 6605, offset 0, flags [DF], proto: TCP (6), length: 1268) as5300-c4-139.cpc.entelchile.net.443 > artem.61628: P 2967:4195(1228) ack 1718 win 15717
|
||||||
|
19:41:59.341771 IP (tos 0x0, ttl 128, id 20155, offset 0, flags [DF], proto: TCP (6), length: 40) artem.61628 > as5300-c4-139.cpc.entelchile.net.443: ., cksum 0xe7a4 (correct), ack 4195 win 34
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
Завершение соединения (листинг~\ref{lst:finish}) происходит в три этапа:
|
||||||
|
\begin{itemize}
|
||||||
|
\item Посылка серверу от клиента флага FIN на завершение соединения.
|
||||||
|
\item Сервер посылает клиенту флаги ответа ACK , FIN, что соединение закрыто.
|
||||||
|
\item После получения этих флагов клиент закрывает соединение и в подтверждение отправляет серверу ACK , что соединение закрыто.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\begin{lstlisting}[caption={Закрытие соединения.}, label={lst:finish}]
|
||||||
|
19:43:04.183260 IP (tos 0x0, ttl 128, id 20206, offset 0, flags [DF], proto: TCP (6), length: 40) artem.61651 > as5300-c4-139.cpc.entelchile.net.443: F, cksum 0xe3cf (correct), 1786:1786(0) ack 4195 win 34
|
||||||
|
19:43:04.452987 IP (tos 0x0, ttl 238, id 45873, offset 0, flags [DF], proto: TCP (6), length: 40) as5300-c4-139.cpc.entelchile.net.443 > artem.61651: ., cksum 0xa648 (correct), ack 1787 win 15785
|
||||||
|
19:43:04.453042 IP (tos 0x0, ttl 238, id 45874, offset 0, flags [DF], proto: TCP (6), length: 40) as5300-c4-139.cpc.entelchile.net.443 > artem.61651: F, cksum 0xa647 (correct), 4195:4195(0) ack 1787 win 15785
|
||||||
|
19:43:04.453067 IP (tos 0x0, ttl 128, id 20208, offset 0, flags [DF], proto: TCP (6), length: 40) artem.61651 > as5300-c4-139.cpc.entelchile.net.443: ., cksum 0xe3ce (correct), ack 4196 win 34
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
|
||||||
|
\end{document}
|
||||||
3
lab3/.gitignore
vendored
Normal file
3
lab3/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
*.jpg
|
||||||
|
*.pdf
|
||||||
|
*.docx
|
||||||
9
lab3/consumer/.gitattributes
vendored
Normal file
9
lab3/consumer/.gitattributes
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#
|
||||||
|
# https://help.github.com/articles/dealing-with-line-endings/
|
||||||
|
#
|
||||||
|
# Linux start script should use lf
|
||||||
|
/gradlew text eol=lf
|
||||||
|
|
||||||
|
# These are Windows script files and should use crlf
|
||||||
|
*.bat text eol=crlf
|
||||||
|
|
||||||
5
lab3/consumer/.gitignore
vendored
Normal file
5
lab3/consumer/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Ignore Gradle project-specific cache directory
|
||||||
|
.gradle
|
||||||
|
|
||||||
|
# Ignore Gradle build output directory
|
||||||
|
build
|
||||||
3
lab3/consumer/.vscode/settings.json
vendored
Normal file
3
lab3/consumer/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"java.configuration.updateBuildConfiguration": "interactive"
|
||||||
|
}
|
||||||
9
lab3/consumer/Dockerfile
Normal file
9
lab3/consumer/Dockerfile
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
FROM gradle:8.13-jdk21
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN gradle build --no-daemon
|
||||||
|
|
||||||
|
CMD ["gradle", "run", "--no-daemon"]
|
||||||
42
lab3/consumer/app/build.gradle
Normal file
42
lab3/consumer/app/build.gradle
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* This file was generated by the Gradle 'init' task.
|
||||||
|
*
|
||||||
|
* This generated file contains a sample Java application project to get you started.
|
||||||
|
* For more details on building Java & JVM projects, please refer to https://docs.gradle.org/8.8/userguide/building_java_projects.html in the Gradle documentation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
// Apply the application plugin to add support for building a CLI application in Java.
|
||||||
|
id 'application'
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
// Use Maven Central for resolving dependencies.
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
// Use JUnit Jupiter for testing.
|
||||||
|
testImplementation libs.junit.jupiter
|
||||||
|
|
||||||
|
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||||
|
|
||||||
|
implementation libs.com.rabbitmq.client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply a specific Java toolchain to ease working on different environments.
|
||||||
|
java {
|
||||||
|
toolchain {
|
||||||
|
languageVersion = JavaLanguageVersion.of(21)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
application {
|
||||||
|
// Define the main class for the application.
|
||||||
|
mainClass = 'dev.tishenko.consumer.Recv'
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named('test') {
|
||||||
|
// Use JUnit Platform for unit tests.
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package dev.tishenko.consumer;
|
||||||
|
|
||||||
|
import com.rabbitmq.client.Channel;
|
||||||
|
import com.rabbitmq.client.Connection;
|
||||||
|
import com.rabbitmq.client.ConnectionFactory;
|
||||||
|
import com.rabbitmq.client.DeliverCallback;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class Recv {
|
||||||
|
private final static String QUEUE_NAME = "hello";
|
||||||
|
|
||||||
|
public static void main(String[] argv) throws Exception {
|
||||||
|
String delayEnv = System.getenv("CONSUMER_DELAY_MS");
|
||||||
|
int delay = delayEnv != null ? Integer.parseInt(delayEnv) : 5000;
|
||||||
|
|
||||||
|
String maxLengthEnv = System.getenv("QUEUE_MAX_LENGTH");
|
||||||
|
int maxLength = maxLengthEnv != null ? Integer.parseInt(maxLengthEnv) : 5;
|
||||||
|
|
||||||
|
String overflowStrategy = System.getenv("QUEUE_OVERFLOW");
|
||||||
|
if (overflowStrategy == null) {
|
||||||
|
overflowStrategy = "drop-head"; // или "reject-publish"
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionFactory factory = new ConnectionFactory();
|
||||||
|
factory.setHost("rabbitmq");
|
||||||
|
|
||||||
|
Connection connection = factory.newConnection();
|
||||||
|
Channel channel = connection.createChannel();
|
||||||
|
|
||||||
|
Map<String, Object> args = new HashMap<>();
|
||||||
|
args.put("x-max-length", maxLength);
|
||||||
|
args.put("x-overflow", overflowStrategy);
|
||||||
|
|
||||||
|
channel.queueDeclare(QUEUE_NAME, false, false, false, args);
|
||||||
|
channel.basicQos(1);
|
||||||
|
|
||||||
|
System.out.println(" [*] Waiting for messages...");
|
||||||
|
|
||||||
|
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
|
||||||
|
String message = new String(delivery.getBody(), "UTF-8");
|
||||||
|
System.out.println(" [x] Received '" + message + "'");
|
||||||
|
try {
|
||||||
|
Thread.sleep(delay);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
|
||||||
|
};
|
||||||
|
|
||||||
|
channel.basicConsume(QUEUE_NAME, false, deliverCallback, consumerTag -> {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
10
lab3/consumer/gradle/libs.versions.toml
Normal file
10
lab3/consumer/gradle/libs.versions.toml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# This file was generated by the Gradle 'init' task.
|
||||||
|
# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format
|
||||||
|
|
||||||
|
[versions]
|
||||||
|
junit-jupiter = "5.10.2"
|
||||||
|
com-rabbitmq-client = "5.25.0"
|
||||||
|
|
||||||
|
[libraries]
|
||||||
|
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit-jupiter" }
|
||||||
|
com-rabbitmq-client = { module = "com.rabbitmq:amqp-client", version.ref = "com-rabbitmq-client"}
|
||||||
BIN
lab3/consumer/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
lab3/consumer/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
7
lab3/consumer/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
7
lab3/consumer/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
|
||||||
|
networkTimeout=10000
|
||||||
|
validateDistributionUrl=true
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
249
lab3/consumer/gradlew
vendored
Normal file
249
lab3/consumer/gradlew
vendored
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright © 2015-2021 the original authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Gradle start up script for POSIX generated by Gradle.
|
||||||
|
#
|
||||||
|
# Important for running:
|
||||||
|
#
|
||||||
|
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||||
|
# noncompliant, but you have some other compliant shell such as ksh or
|
||||||
|
# bash, then to run this script, type that shell name before the whole
|
||||||
|
# command line, like:
|
||||||
|
#
|
||||||
|
# ksh Gradle
|
||||||
|
#
|
||||||
|
# Busybox and similar reduced shells will NOT work, because this script
|
||||||
|
# requires all of these POSIX shell features:
|
||||||
|
# * functions;
|
||||||
|
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||||
|
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||||
|
# * compound commands having a testable exit status, especially «case»;
|
||||||
|
# * various built-in commands including «command», «set», and «ulimit».
|
||||||
|
#
|
||||||
|
# Important for patching:
|
||||||
|
#
|
||||||
|
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||||
|
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||||
|
#
|
||||||
|
# The "traditional" practice of packing multiple parameters into a
|
||||||
|
# space-separated string is a well documented source of bugs and security
|
||||||
|
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||||
|
# options in "$@", and eventually passing that to Java.
|
||||||
|
#
|
||||||
|
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||||
|
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||||
|
# see the in-line comments for details.
|
||||||
|
#
|
||||||
|
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||||
|
# Darwin, MinGW, and NonStop.
|
||||||
|
#
|
||||||
|
# (3) This script is generated from the Groovy template
|
||||||
|
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
|
# within the Gradle project.
|
||||||
|
#
|
||||||
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
app_path=$0
|
||||||
|
|
||||||
|
# Need this for daisy-chained symlinks.
|
||||||
|
while
|
||||||
|
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||||
|
[ -h "$app_path" ]
|
||||||
|
do
|
||||||
|
ls=$( ls -ld "$app_path" )
|
||||||
|
link=${ls#*' -> '}
|
||||||
|
case $link in #(
|
||||||
|
/*) app_path=$link ;; #(
|
||||||
|
*) app_path=$APP_HOME$link ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# This is normally unused
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
APP_BASE_NAME=${0##*/}
|
||||||
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
|
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD=maximum
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "$( uname )" in #(
|
||||||
|
CYGWIN* ) cygwin=true ;; #(
|
||||||
|
Darwin* ) darwin=true ;; #(
|
||||||
|
MSYS* | MINGW* ) msys=true ;; #(
|
||||||
|
NONSTOP* ) nonstop=true ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||||
|
else
|
||||||
|
JAVACMD=$JAVA_HOME/bin/java
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD=java
|
||||||
|
if ! command -v java >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
|
case $MAX_FD in #(
|
||||||
|
max*)
|
||||||
|
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||||
|
# shellcheck disable=SC2039,SC3045
|
||||||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
|
warn "Could not query maximum file descriptor limit"
|
||||||
|
esac
|
||||||
|
case $MAX_FD in #(
|
||||||
|
'' | soft) :;; #(
|
||||||
|
*)
|
||||||
|
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||||
|
# shellcheck disable=SC2039,SC3045
|
||||||
|
ulimit -n "$MAX_FD" ||
|
||||||
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, stacking in reverse order:
|
||||||
|
# * args from the command line
|
||||||
|
# * the main class name
|
||||||
|
# * -classpath
|
||||||
|
# * -D...appname settings
|
||||||
|
# * --module-path (only if needed)
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||||
|
|
||||||
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
|
if "$cygwin" || "$msys" ; then
|
||||||
|
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||||
|
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||||
|
|
||||||
|
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||||
|
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
for arg do
|
||||||
|
if
|
||||||
|
case $arg in #(
|
||||||
|
-*) false ;; # don't mess with options #(
|
||||||
|
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||||
|
[ -e "$t" ] ;; #(
|
||||||
|
*) false ;;
|
||||||
|
esac
|
||||||
|
then
|
||||||
|
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||||
|
fi
|
||||||
|
# Roll the args list around exactly as many times as the number of
|
||||||
|
# args, so each arg winds up back in the position where it started, but
|
||||||
|
# possibly modified.
|
||||||
|
#
|
||||||
|
# NB: a `for` loop captures its iteration list before it begins, so
|
||||||
|
# changing the positional parameters here affects neither the number of
|
||||||
|
# iterations, nor the values presented in `arg`.
|
||||||
|
shift # remove old arg
|
||||||
|
set -- "$@" "$arg" # push replacement arg
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
|
# Collect all arguments for the java command:
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||||
|
# and any embedded shellness will be escaped.
|
||||||
|
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||||
|
# treated as '${Hostname}' itself on the command line.
|
||||||
|
|
||||||
|
set -- \
|
||||||
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
-classpath "$CLASSPATH" \
|
||||||
|
org.gradle.wrapper.GradleWrapperMain \
|
||||||
|
"$@"
|
||||||
|
|
||||||
|
# Stop when "xargs" is not available.
|
||||||
|
if ! command -v xargs >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "xargs is not available"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use "xargs" to parse quoted args.
|
||||||
|
#
|
||||||
|
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||||
|
#
|
||||||
|
# In Bash we could simply go:
|
||||||
|
#
|
||||||
|
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||||
|
# set -- "${ARGS[@]}" "$@"
|
||||||
|
#
|
||||||
|
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||||
|
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||||
|
# character that might be a shell metacharacter, then use eval to reverse
|
||||||
|
# that process (while maintaining the separation between arguments), and wrap
|
||||||
|
# the whole thing up as a single "set" statement.
|
||||||
|
#
|
||||||
|
# This will of course break if any of these variables contains a newline or
|
||||||
|
# an unmatched quote.
|
||||||
|
#
|
||||||
|
|
||||||
|
eval "set -- $(
|
||||||
|
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||||
|
xargs -n1 |
|
||||||
|
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||||
|
tr '\n' ' '
|
||||||
|
)" '"$@"'
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
||||||
92
lab3/consumer/gradlew.bat
vendored
Normal file
92
lab3/consumer/gradlew.bat
vendored
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
@rem
|
||||||
|
@rem Copyright 2015 the original author or authors.
|
||||||
|
@rem
|
||||||
|
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@rem you may not use this file except in compliance with the License.
|
||||||
|
@rem You may obtain a copy of the License at
|
||||||
|
@rem
|
||||||
|
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@rem
|
||||||
|
@rem Unless required by applicable law or agreed to in writing, software
|
||||||
|
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@rem See the License for the specific language governing permissions and
|
||||||
|
@rem limitations under the License.
|
||||||
|
@rem
|
||||||
|
|
||||||
|
@if "%DEBUG%"=="" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%"=="" set DIRNAME=.
|
||||||
|
@rem This is normally unused
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
|
echo. 1>&2
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||||
|
echo. 1>&2
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
|
echo. 1>&2
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||||
|
echo. 1>&2
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
set EXIT_CODE=%ERRORLEVEL%
|
||||||
|
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||||
|
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||||
|
exit /b %EXIT_CODE%
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
||||||
14
lab3/consumer/settings.gradle
Normal file
14
lab3/consumer/settings.gradle
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* This file was generated by the Gradle 'init' task.
|
||||||
|
*
|
||||||
|
* The settings file is used to specify which projects to include in your build.
|
||||||
|
* For more detailed information on multi-project builds, please refer to https://docs.gradle.org/8.8/userguide/multi_project_builds.html in the Gradle documentation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
// Apply the foojay-resolver plugin to allow automatic download of JDKs
|
||||||
|
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0'
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.name = 'consumer'
|
||||||
|
include('app')
|
||||||
53
lab3/docker-compose.yml
Normal file
53
lab3/docker-compose.yml
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
services:
|
||||||
|
rabbitmq:
|
||||||
|
image: rabbitmq:4.0-management
|
||||||
|
hostname: rabbitmq
|
||||||
|
container_name: rabbitmq
|
||||||
|
ports:
|
||||||
|
- "5672:5672"
|
||||||
|
- "15672:15672"
|
||||||
|
networks:
|
||||||
|
- rabbitnet
|
||||||
|
|
||||||
|
producer1:
|
||||||
|
container_name: producer1
|
||||||
|
build:
|
||||||
|
context: ./producer
|
||||||
|
depends_on:
|
||||||
|
- rabbitmq
|
||||||
|
- consumer
|
||||||
|
environment:
|
||||||
|
- PRODUCER_NAME=first
|
||||||
|
- PRODUCER_DELAY_MS=1000
|
||||||
|
networks:
|
||||||
|
- rabbitnet
|
||||||
|
|
||||||
|
producer2:
|
||||||
|
container_name: producer2
|
||||||
|
build:
|
||||||
|
context: ./producer
|
||||||
|
depends_on:
|
||||||
|
- rabbitmq
|
||||||
|
- consumer
|
||||||
|
environment:
|
||||||
|
- PRODUCER_NAME=second
|
||||||
|
- PRODUCER_DELAY_MS=1000
|
||||||
|
networks:
|
||||||
|
- rabbitnet
|
||||||
|
|
||||||
|
consumer:
|
||||||
|
container_name: consumer
|
||||||
|
build:
|
||||||
|
context: ./consumer
|
||||||
|
depends_on:
|
||||||
|
- rabbitmq
|
||||||
|
environment:
|
||||||
|
- CONSUMER_DELAY_MS=1000
|
||||||
|
- QUEUE_MAX_LENGTH=10
|
||||||
|
- QUEUE_OVERFLOW=reject-publish # drop-head, reject-publish
|
||||||
|
networks:
|
||||||
|
- rabbitnet
|
||||||
|
|
||||||
|
networks:
|
||||||
|
rabbitnet:
|
||||||
|
driver: bridge
|
||||||
8
lab3/my-variant.txt
Normal file
8
lab3/my-variant.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Используя docker создать контейнеры, необходимые для реализации
|
||||||
|
следующего функционала с использованием RabbitMQ/Kafka,
|
||||||
|
а также показать, как именно осуществляется передача в этих условиях:
|
||||||
|
|
||||||
|
10. Организовать отправку сообщений от двух отправителей одному получателю,
|
||||||
|
получатель читает сообщения значительно реже их отправки
|
||||||
|
и происходит переполнение очереди. Задавать раличные стратегии
|
||||||
|
переполнения очереди, показать в чем разница.
|
||||||
9
lab3/producer/.gitattributes
vendored
Normal file
9
lab3/producer/.gitattributes
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#
|
||||||
|
# https://help.github.com/articles/dealing-with-line-endings/
|
||||||
|
#
|
||||||
|
# Linux start script should use lf
|
||||||
|
/gradlew text eol=lf
|
||||||
|
|
||||||
|
# These are Windows script files and should use crlf
|
||||||
|
*.bat text eol=crlf
|
||||||
|
|
||||||
5
lab3/producer/.gitignore
vendored
Normal file
5
lab3/producer/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Ignore Gradle project-specific cache directory
|
||||||
|
.gradle
|
||||||
|
|
||||||
|
# Ignore Gradle build output directory
|
||||||
|
build
|
||||||
3
lab3/producer/.vscode/settings.json
vendored
Normal file
3
lab3/producer/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"java.configuration.updateBuildConfiguration": "interactive"
|
||||||
|
}
|
||||||
9
lab3/producer/Dockerfile
Normal file
9
lab3/producer/Dockerfile
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
FROM gradle:8.13-jdk21
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN gradle build --no-daemon
|
||||||
|
|
||||||
|
CMD ["gradle", "run", "--no-daemon"]
|
||||||
42
lab3/producer/app/build.gradle
Normal file
42
lab3/producer/app/build.gradle
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* This file was generated by the Gradle 'init' task.
|
||||||
|
*
|
||||||
|
* This generated file contains a sample Java application project to get you started.
|
||||||
|
* For more details on building Java & JVM projects, please refer to https://docs.gradle.org/8.8/userguide/building_java_projects.html in the Gradle documentation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
// Apply the application plugin to add support for building a CLI application in Java.
|
||||||
|
id 'application'
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
// Use Maven Central for resolving dependencies.
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
// Use JUnit Jupiter for testing.
|
||||||
|
testImplementation libs.junit.jupiter
|
||||||
|
|
||||||
|
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||||
|
|
||||||
|
implementation libs.com.rabbitmq.client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply a specific Java toolchain to ease working on different environments.
|
||||||
|
java {
|
||||||
|
toolchain {
|
||||||
|
languageVersion = JavaLanguageVersion.of(21)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
application {
|
||||||
|
// Define the main class for the application.
|
||||||
|
mainClass = 'dev.tishenko.producer.Send'
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named('test') {
|
||||||
|
// Use JUnit Platform for unit tests.
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package dev.tishenko.producer;
|
||||||
|
|
||||||
|
import com.rabbitmq.client.ConnectionFactory;
|
||||||
|
import com.rabbitmq.client.Connection;
|
||||||
|
import com.rabbitmq.client.Channel;
|
||||||
|
|
||||||
|
public class Send {
|
||||||
|
private static final String QUEUE_NAME = "hello";
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
String name = System.getenv("PRODUCER_NAME");
|
||||||
|
name = name != null ? name : "";
|
||||||
|
|
||||||
|
String delayEnv = System.getenv("PRODUCER_DELAY_MS");
|
||||||
|
int delay = delayEnv != null ? Integer.parseInt(delayEnv) : 1000;
|
||||||
|
|
||||||
|
ConnectionFactory factory = new ConnectionFactory();
|
||||||
|
factory.setHost("rabbitmq");
|
||||||
|
|
||||||
|
try (Connection connection = factory.newConnection();
|
||||||
|
Channel channel = connection.createChannel()) {
|
||||||
|
channel.queueDeclarePassive(QUEUE_NAME);
|
||||||
|
channel.confirmSelect();
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
while (true) {
|
||||||
|
String message = "Message from " + name + " #" + count++;
|
||||||
|
channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
|
||||||
|
if (!channel.waitForConfirms()) {
|
||||||
|
System.out.println(" [!] Message was NOT confirmed!");
|
||||||
|
} else {
|
||||||
|
System.out.println(" [x] Sent '" + message + "'");
|
||||||
|
}
|
||||||
|
Thread.sleep(delay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
lab3/producer/gradle/libs.versions.toml
Normal file
10
lab3/producer/gradle/libs.versions.toml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# This file was generated by the Gradle 'init' task.
|
||||||
|
# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format
|
||||||
|
|
||||||
|
[versions]
|
||||||
|
junit-jupiter = "5.10.2"
|
||||||
|
com-rabbitmq-client = "5.25.0"
|
||||||
|
|
||||||
|
[libraries]
|
||||||
|
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit-jupiter" }
|
||||||
|
com-rabbitmq-client = { module = "com.rabbitmq:amqp-client", version.ref = "com-rabbitmq-client"}
|
||||||
BIN
lab3/producer/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
lab3/producer/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
7
lab3/producer/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
7
lab3/producer/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
|
||||||
|
networkTimeout=10000
|
||||||
|
validateDistributionUrl=true
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
249
lab3/producer/gradlew
vendored
Normal file
249
lab3/producer/gradlew
vendored
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright © 2015-2021 the original authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Gradle start up script for POSIX generated by Gradle.
|
||||||
|
#
|
||||||
|
# Important for running:
|
||||||
|
#
|
||||||
|
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||||
|
# noncompliant, but you have some other compliant shell such as ksh or
|
||||||
|
# bash, then to run this script, type that shell name before the whole
|
||||||
|
# command line, like:
|
||||||
|
#
|
||||||
|
# ksh Gradle
|
||||||
|
#
|
||||||
|
# Busybox and similar reduced shells will NOT work, because this script
|
||||||
|
# requires all of these POSIX shell features:
|
||||||
|
# * functions;
|
||||||
|
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||||
|
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||||
|
# * compound commands having a testable exit status, especially «case»;
|
||||||
|
# * various built-in commands including «command», «set», and «ulimit».
|
||||||
|
#
|
||||||
|
# Important for patching:
|
||||||
|
#
|
||||||
|
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||||
|
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||||
|
#
|
||||||
|
# The "traditional" practice of packing multiple parameters into a
|
||||||
|
# space-separated string is a well documented source of bugs and security
|
||||||
|
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||||
|
# options in "$@", and eventually passing that to Java.
|
||||||
|
#
|
||||||
|
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||||
|
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||||
|
# see the in-line comments for details.
|
||||||
|
#
|
||||||
|
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||||
|
# Darwin, MinGW, and NonStop.
|
||||||
|
#
|
||||||
|
# (3) This script is generated from the Groovy template
|
||||||
|
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
|
# within the Gradle project.
|
||||||
|
#
|
||||||
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
app_path=$0
|
||||||
|
|
||||||
|
# Need this for daisy-chained symlinks.
|
||||||
|
while
|
||||||
|
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||||
|
[ -h "$app_path" ]
|
||||||
|
do
|
||||||
|
ls=$( ls -ld "$app_path" )
|
||||||
|
link=${ls#*' -> '}
|
||||||
|
case $link in #(
|
||||||
|
/*) app_path=$link ;; #(
|
||||||
|
*) app_path=$APP_HOME$link ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# This is normally unused
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
APP_BASE_NAME=${0##*/}
|
||||||
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
|
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD=maximum
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "$( uname )" in #(
|
||||||
|
CYGWIN* ) cygwin=true ;; #(
|
||||||
|
Darwin* ) darwin=true ;; #(
|
||||||
|
MSYS* | MINGW* ) msys=true ;; #(
|
||||||
|
NONSTOP* ) nonstop=true ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||||
|
else
|
||||||
|
JAVACMD=$JAVA_HOME/bin/java
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD=java
|
||||||
|
if ! command -v java >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
|
case $MAX_FD in #(
|
||||||
|
max*)
|
||||||
|
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||||
|
# shellcheck disable=SC2039,SC3045
|
||||||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
|
warn "Could not query maximum file descriptor limit"
|
||||||
|
esac
|
||||||
|
case $MAX_FD in #(
|
||||||
|
'' | soft) :;; #(
|
||||||
|
*)
|
||||||
|
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||||
|
# shellcheck disable=SC2039,SC3045
|
||||||
|
ulimit -n "$MAX_FD" ||
|
||||||
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, stacking in reverse order:
|
||||||
|
# * args from the command line
|
||||||
|
# * the main class name
|
||||||
|
# * -classpath
|
||||||
|
# * -D...appname settings
|
||||||
|
# * --module-path (only if needed)
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||||
|
|
||||||
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
|
if "$cygwin" || "$msys" ; then
|
||||||
|
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||||
|
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||||
|
|
||||||
|
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||||
|
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
for arg do
|
||||||
|
if
|
||||||
|
case $arg in #(
|
||||||
|
-*) false ;; # don't mess with options #(
|
||||||
|
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||||
|
[ -e "$t" ] ;; #(
|
||||||
|
*) false ;;
|
||||||
|
esac
|
||||||
|
then
|
||||||
|
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||||
|
fi
|
||||||
|
# Roll the args list around exactly as many times as the number of
|
||||||
|
# args, so each arg winds up back in the position where it started, but
|
||||||
|
# possibly modified.
|
||||||
|
#
|
||||||
|
# NB: a `for` loop captures its iteration list before it begins, so
|
||||||
|
# changing the positional parameters here affects neither the number of
|
||||||
|
# iterations, nor the values presented in `arg`.
|
||||||
|
shift # remove old arg
|
||||||
|
set -- "$@" "$arg" # push replacement arg
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
|
# Collect all arguments for the java command:
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||||
|
# and any embedded shellness will be escaped.
|
||||||
|
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||||
|
# treated as '${Hostname}' itself on the command line.
|
||||||
|
|
||||||
|
set -- \
|
||||||
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
-classpath "$CLASSPATH" \
|
||||||
|
org.gradle.wrapper.GradleWrapperMain \
|
||||||
|
"$@"
|
||||||
|
|
||||||
|
# Stop when "xargs" is not available.
|
||||||
|
if ! command -v xargs >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "xargs is not available"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use "xargs" to parse quoted args.
|
||||||
|
#
|
||||||
|
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||||
|
#
|
||||||
|
# In Bash we could simply go:
|
||||||
|
#
|
||||||
|
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||||
|
# set -- "${ARGS[@]}" "$@"
|
||||||
|
#
|
||||||
|
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||||
|
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||||
|
# character that might be a shell metacharacter, then use eval to reverse
|
||||||
|
# that process (while maintaining the separation between arguments), and wrap
|
||||||
|
# the whole thing up as a single "set" statement.
|
||||||
|
#
|
||||||
|
# This will of course break if any of these variables contains a newline or
|
||||||
|
# an unmatched quote.
|
||||||
|
#
|
||||||
|
|
||||||
|
eval "set -- $(
|
||||||
|
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||||
|
xargs -n1 |
|
||||||
|
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||||
|
tr '\n' ' '
|
||||||
|
)" '"$@"'
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
||||||
92
lab3/producer/gradlew.bat
vendored
Normal file
92
lab3/producer/gradlew.bat
vendored
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
@rem
|
||||||
|
@rem Copyright 2015 the original author or authors.
|
||||||
|
@rem
|
||||||
|
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@rem you may not use this file except in compliance with the License.
|
||||||
|
@rem You may obtain a copy of the License at
|
||||||
|
@rem
|
||||||
|
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@rem
|
||||||
|
@rem Unless required by applicable law or agreed to in writing, software
|
||||||
|
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@rem See the License for the specific language governing permissions and
|
||||||
|
@rem limitations under the License.
|
||||||
|
@rem
|
||||||
|
|
||||||
|
@if "%DEBUG%"=="" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%"=="" set DIRNAME=.
|
||||||
|
@rem This is normally unused
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
|
echo. 1>&2
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||||
|
echo. 1>&2
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
|
echo. 1>&2
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||||
|
echo. 1>&2
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
set EXIT_CODE=%ERRORLEVEL%
|
||||||
|
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||||
|
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||||
|
exit /b %EXIT_CODE%
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
||||||
14
lab3/producer/settings.gradle
Normal file
14
lab3/producer/settings.gradle
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* This file was generated by the Gradle 'init' task.
|
||||||
|
*
|
||||||
|
* The settings file is used to specify which projects to include in your build.
|
||||||
|
* For more detailed information on multi-project builds, please refer to https://docs.gradle.org/8.8/userguide/multi_project_builds.html in the Gradle documentation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
// Apply the foojay-resolver plugin to allow automatic download of JDKs
|
||||||
|
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0'
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.name = 'producer'
|
||||||
|
include('app')
|
||||||
5
lab3/report/.gitignore
vendored
Normal file
5
lab3/report/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
**/*
|
||||||
|
!.gitignore
|
||||||
|
!report.tex
|
||||||
|
!img
|
||||||
|
!img/**
|
||||||
464
lab3/report/report.tex
Normal file
464
lab3/report/report.tex
Normal file
@@ -0,0 +1,464 @@
|
|||||||
|
\documentclass[a4paper, final]{article}
|
||||||
|
%\usepackage{literat} % Нормальные шрифты
|
||||||
|
\usepackage[14pt]{extsizes} % для того чтобы задать нестандартный 14-ый размер шрифта
|
||||||
|
\usepackage{tabularx}
|
||||||
|
\usepackage[T2A]{fontenc}
|
||||||
|
\usepackage[utf8]{inputenc}
|
||||||
|
\usepackage[russian]{babel}
|
||||||
|
\usepackage{amsmath}
|
||||||
|
\usepackage[left=25mm, top=20mm, right=20mm, bottom=20mm, footskip=10mm]{geometry}
|
||||||
|
\usepackage{ragged2e} %для растягивания по ширине
|
||||||
|
\usepackage{setspace} %для межстрочно го интервала
|
||||||
|
\usepackage{moreverb} %для работы с листингами
|
||||||
|
\usepackage{indentfirst} % для абзацного отступа
|
||||||
|
\usepackage{moreverb} %для печати в листинге исходного кода программ
|
||||||
|
\usepackage{pdfpages} %для вставки других pdf файлов
|
||||||
|
\usepackage{tikz}
|
||||||
|
\usepackage{graphicx}
|
||||||
|
\usepackage{afterpage}
|
||||||
|
\usepackage{longtable}
|
||||||
|
\usepackage{float}
|
||||||
|
\usepackage{tabularx}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
% \usepackage[paper=A4,DIV=12]{typearea}
|
||||||
|
\usepackage{pdflscape}
|
||||||
|
% \usepackage{lscape}
|
||||||
|
|
||||||
|
\usepackage{array}
|
||||||
|
\usepackage{multirow}
|
||||||
|
|
||||||
|
\renewcommand\verbatimtabsize{4\relax}
|
||||||
|
\renewcommand\listingoffset{0.2em} %отступ от номеров строк в листинге
|
||||||
|
\renewcommand{\arraystretch}{1.4} % изменяю высоту строки в таблице
|
||||||
|
\usepackage[font=small, singlelinecheck=false, justification=centering, format=plain, labelsep=period]{caption} %для настройки заголовка таблицы
|
||||||
|
\usepackage{listings} %листинги
|
||||||
|
\usepackage{xcolor} % цвета
|
||||||
|
\usepackage{hyperref}% для гиперссылок
|
||||||
|
\usepackage{enumitem} %для перечислений
|
||||||
|
|
||||||
|
\newcommand{\specialcell}[2][l]{\begin{tabular}[#1]{@{}l@{}}#2\end{tabular}}
|
||||||
|
|
||||||
|
|
||||||
|
\setlist[enumerate,itemize]{leftmargin=1.2cm} %отступ в перечислениях
|
||||||
|
|
||||||
|
\hypersetup{colorlinks,
|
||||||
|
allcolors=[RGB]{010 090 200}} %красивые гиперссылки (не красные)
|
||||||
|
|
||||||
|
% подгружаемые языки — подробнее в документации listings (это всё для листингов)
|
||||||
|
\lstloadlanguages{ SQL}
|
||||||
|
% включаем кириллицу и добавляем кое−какие опции
|
||||||
|
\lstset{tabsize=2,
|
||||||
|
breaklines,
|
||||||
|
basicstyle=\footnotesize,
|
||||||
|
columns=fullflexible,
|
||||||
|
flexiblecolumns,
|
||||||
|
numbers=left,
|
||||||
|
numberstyle={\footnotesize},
|
||||||
|
keywordstyle=\color{blue},
|
||||||
|
inputencoding=cp1251,
|
||||||
|
extendedchars=true
|
||||||
|
}
|
||||||
|
\lstdefinelanguage{MyC}{
|
||||||
|
language=SQL,
|
||||||
|
% ndkeywordstyle=\color{darkgray}\bfseries,
|
||||||
|
% identifierstyle=\color{black},
|
||||||
|
% morecomment=[n]{/**}{*/},
|
||||||
|
% commentstyle=\color{blue}\ttfamily,
|
||||||
|
% stringstyle=\color{red}\ttfamily,
|
||||||
|
% morestring=[b]",
|
||||||
|
% showstringspaces=false,
|
||||||
|
% morecomment=[l][\color{gray}]{//},
|
||||||
|
keepspaces=true,
|
||||||
|
escapechar=\%,
|
||||||
|
texcl=true
|
||||||
|
}
|
||||||
|
|
||||||
|
\textheight=24cm % высота текста
|
||||||
|
\textwidth=16cm % ширина текста
|
||||||
|
\oddsidemargin=0pt % отступ от левого края
|
||||||
|
\topmargin=-1.5cm % отступ от верхнего края
|
||||||
|
\parindent=24pt % абзацный отступ
|
||||||
|
\parskip=5pt % интервал между абзацами
|
||||||
|
\tolerance=2000 % терпимость к "жидким" строкам
|
||||||
|
\flushbottom % выравнивание высоты страниц
|
||||||
|
|
||||||
|
|
||||||
|
% Настройка листингов
|
||||||
|
\lstset{
|
||||||
|
language=C++,
|
||||||
|
extendedchars=\true,
|
||||||
|
inputencoding=utf8,
|
||||||
|
keepspaces=true,
|
||||||
|
% captionpos=b, % подписи листингов снизу
|
||||||
|
}
|
||||||
|
|
||||||
|
\begin{document} % начало документа
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
% НАЧАЛО ТИТУЛЬНОГО ЛИСТА
|
||||||
|
\begin{center}
|
||||||
|
\hfill \break
|
||||||
|
\hfill \break
|
||||||
|
\normalsize{МИНИСТЕРСТВО НАУКИ И ВЫСШЕГО ОБРАЗОВАНИЯ РОССИЙСКОЙ ФЕДЕРАЦИИ\\
|
||||||
|
федеральное государственное автономное образовательное учреждение высшего образования «Санкт-Петербургский политехнический университет Петра Великого»\\[10pt]}
|
||||||
|
\normalsize{Институт компьютерных наук и кибербезопасности}\\[10pt]
|
||||||
|
\normalsize{Высшая школа технологий искусственного интеллекта}\\[10pt]
|
||||||
|
\normalsize{Направление: 02.03.01 <<Математика и компьютерные науки>>}\\
|
||||||
|
|
||||||
|
\hfill \break
|
||||||
|
\hfill \break
|
||||||
|
\hfill \break
|
||||||
|
\hfill \break
|
||||||
|
\large{Лабораторная работа №3}\\
|
||||||
|
\large{<<Межпроцессорное взаимодействие с помощью RabbitMQ>>}\\
|
||||||
|
\large{по дисциплине <<Сети ЭВМ и телекоммуникации компьютерных сетей>>}\\
|
||||||
|
\hfill \break
|
||||||
|
|
||||||
|
% \hfill \break
|
||||||
|
\hfill \break
|
||||||
|
\end{center}
|
||||||
|
|
||||||
|
\small{
|
||||||
|
\begin{tabular}{lrrl}
|
||||||
|
\!\!\!Студент, & \hspace{2cm} & & \\
|
||||||
|
\!\!\!группы 5130201/20102 & \hspace{2cm} & \underline{\hspace{3cm}} &Тищенко А. А. \\\\
|
||||||
|
\!\!\!Преподаватель & \hspace{2cm} & \underline{\hspace{3cm}} & Мулюха В. А. \\\\
|
||||||
|
&&\hspace{4cm}
|
||||||
|
\end{tabular}
|
||||||
|
\begin{flushright}
|
||||||
|
<<\underline{\hspace{1cm}}>>\underline{\hspace{2.5cm}} 2025г.
|
||||||
|
\end{flushright}
|
||||||
|
}
|
||||||
|
|
||||||
|
\hfill \break
|
||||||
|
% \hfill \break
|
||||||
|
\begin{center} \small{Санкт-Петербург, 2025} \end{center}
|
||||||
|
\thispagestyle{empty} % выключаем отображение номера для этой страницы
|
||||||
|
|
||||||
|
% КОНЕЦ ТИТУЛЬНОГО ЛИСТА
|
||||||
|
% \newpage
|
||||||
|
% \tableofcontents
|
||||||
|
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Постановка задачи}
|
||||||
|
Используя docker создать контейнеры, необходимые для реализации
|
||||||
|
следующего функционала с использованием RabbitMQ,
|
||||||
|
а также показать, как именно осуществляется передача в этих условиях:
|
||||||
|
|
||||||
|
\textit{Вариант 10}. Организовать отправку сообщений от двух отправителей одному получателю,
|
||||||
|
получатель читает сообщения значительно реже их отправки
|
||||||
|
и происходит переполнение очереди. Задавать раличные стратегии
|
||||||
|
переполнения очереди, показать в чем разница.
|
||||||
|
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Ход работы}
|
||||||
|
|
||||||
|
\subsection{Код программы получателя}
|
||||||
|
Класс `Recv` из пакета `dev.tishenko.consumer` реализует потребителя сообщений из очереди RabbitMQ с именем `hello`. Он подключается к брокеру `rabbitmq`, создаёт очередь с ограниченной длиной (`x-max-length`) и стратегией переполнения (`x-overflow`), параметры которых настраиваются через переменные окружения. Консьюмер асинхронно принимает сообщения и после каждой обработки (с задержкой, заданной через `CONSUMER\_DELAY\_MS`) подтверждает получение сообщения. Благодаря настройке `basicQos(1)` сообщения обрабатываются по одному, что обеспечивает контроль нагрузки и предотвращает переполнение очереди необработанными сообщениями.
|
||||||
|
|
||||||
|
\begin{lstlisting}[label={lst:}]
|
||||||
|
package dev.tishenko.consumer;
|
||||||
|
|
||||||
|
import com.rabbitmq.client.Channel;
|
||||||
|
import com.rabbitmq.client.Connection;
|
||||||
|
import com.rabbitmq.client.ConnectionFactory;
|
||||||
|
import com.rabbitmq.client.DeliverCallback;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class Recv {
|
||||||
|
private final static String QUEUE_NAME = "hello";
|
||||||
|
|
||||||
|
public static void main(String[] argv) throws Exception {
|
||||||
|
String delayEnv = System.getenv("CONSUMER_DELAY_MS");
|
||||||
|
int delay = delayEnv != null ? Integer.parseInt(delayEnv) : 5000;
|
||||||
|
|
||||||
|
String maxLengthEnv = System.getenv("QUEUE_MAX_LENGTH");
|
||||||
|
int maxLength = maxLengthEnv != null ? Integer.parseInt(maxLengthEnv) : 5;
|
||||||
|
|
||||||
|
String overflowStrategy = System.getenv("QUEUE_OVERFLOW");
|
||||||
|
if (overflowStrategy == null) {
|
||||||
|
overflowStrategy = "drop-head"; // или "reject-publish"
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionFactory factory = new ConnectionFactory();
|
||||||
|
factory.setHost("rabbitmq");
|
||||||
|
|
||||||
|
Connection connection = factory.newConnection();
|
||||||
|
Channel channel = connection.createChannel();
|
||||||
|
|
||||||
|
Map<String, Object> args = new HashMap<>();
|
||||||
|
args.put("x-max-length", maxLength);
|
||||||
|
args.put("x-overflow", overflowStrategy);
|
||||||
|
|
||||||
|
channel.queueDeclare(QUEUE_NAME, false, false, false, args);
|
||||||
|
channel.basicQos(1);
|
||||||
|
|
||||||
|
System.out.println(" [*] Waiting for messages...");
|
||||||
|
|
||||||
|
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
|
||||||
|
String message = new String(delivery.getBody(), "UTF-8");
|
||||||
|
System.out.println(" [x] Received '" + message + "'");
|
||||||
|
try {
|
||||||
|
Thread.sleep(delay);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
|
||||||
|
};
|
||||||
|
|
||||||
|
channel.basicConsume(QUEUE_NAME, false, deliverCallback, consumerTag -> {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
|
||||||
|
\subsection{Код программы отправителя}
|
||||||
|
|
||||||
|
Класс `Send` представляет собой простого отправителя сообщений для RabbitMQ. Он подключается к брокеру (по адресу контейнера `rabbitmq`), использует очередь с именем `hello` (предполагая, что она уже существует), и в бесконечном цикле отправляет в неё сообщения с уникальным номером, указывая имя продюсера, полученное из переменной окружения `PRODUCER\_NAME`. Задержка между отправками настраивается через переменную `PRODUCER\_DELAY\_MS`. После каждой отправки ожидается подтверждение от брокера, иначе выводится предупреждение.
|
||||||
|
|
||||||
|
\begin{lstlisting}[label={lst:}]
|
||||||
|
package dev.tishenko.producer;
|
||||||
|
|
||||||
|
import com.rabbitmq.client.ConnectionFactory;
|
||||||
|
import com.rabbitmq.client.Connection;
|
||||||
|
import com.rabbitmq.client.Channel;
|
||||||
|
|
||||||
|
public class Send {
|
||||||
|
private static final String QUEUE_NAME = "hello";
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
String name = System.getenv("PRODUCER_NAME");
|
||||||
|
name = name != null ? name : "";
|
||||||
|
|
||||||
|
String delayEnv = System.getenv("PRODUCER_DELAY_MS");
|
||||||
|
int delay = delayEnv != null ? Integer.parseInt(delayEnv) : 1000;
|
||||||
|
|
||||||
|
ConnectionFactory factory = new ConnectionFactory();
|
||||||
|
factory.setHost("rabbitmq");
|
||||||
|
|
||||||
|
try (Connection connection = factory.newConnection();
|
||||||
|
Channel channel = connection.createChannel()) {
|
||||||
|
channel.queueDeclarePassive(QUEUE_NAME);
|
||||||
|
channel.confirmSelect();
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
while (true) {
|
||||||
|
String message = "Message from " + name + " #" + count++;
|
||||||
|
channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
|
||||||
|
if (!channel.waitForConfirms()) {
|
||||||
|
System.out.println(" [!] Message was NOT confirmed!");
|
||||||
|
} else {
|
||||||
|
System.out.println(" [x] Sent '" + message + "'");
|
||||||
|
}
|
||||||
|
Thread.sleep(delay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
\subsection{Dockerfile для отправителя и получателя}
|
||||||
|
Для программы отправителя и получателя сообщений были созданы два идентичных Dockerfile. Программы написаны на Java и собирались с помощью Gradle, поэтому используется базовый образ \texttt{gradle:8.13-jdk21}.
|
||||||
|
|
||||||
|
\begin{lstlisting}[label={lst:}]
|
||||||
|
FROM gradle:8.13-jdk21
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN gradle build --no-daemon
|
||||||
|
|
||||||
|
CMD ["gradle", "run", "--no-daemon"]
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
\subsection{Настройка Docker Compose}
|
||||||
|
Файл \texttt{docker-compose.yml} нужен, чтобы управлять сразу несколькими контейнерами. Файл, представленный ниже, состоит из следующих секций:
|
||||||
|
\begin{itemize}
|
||||||
|
\item \textbf{rabbitmq} -- контейнер с RabbitMQ. Используется образ \texttt{rabbitmq:4.0-management}, который включает веб-интерфейс для мониторинга. Порты 5672 и 15672 проброшены наружу для AMQP-протокола и веб-интерфейса соответственно.
|
||||||
|
|
||||||
|
\item \textbf{producer1} -- первый продюсер, отправляющий сообщения в RabbitMQ. Сборка производится из локальной директории \texttt{./producer}. В переменных окружения задаётся имя продюсера (\texttt{PRODUCER\_NAME}) и задержка между отправкой сообщений в миллисекундах (\texttt{PRODUCER\_DELAY\_MS}).
|
||||||
|
|
||||||
|
\item \textbf{producer2} -- второй продюсер, аналогичный первому.
|
||||||
|
|
||||||
|
\item \textbf{consumer} -- получатель сообщений из очереди RabbitMQ. Сборка происходит из директории \texttt{./consumer}. Консьюмер обрабатывает сообщения с заданной задержкой (\texttt{CONSUMER\_DELAY\_MS}). Дополнительно задаются параметры очереди: максимальная длина (\texttt{QUEUE\_MAX\_LENGTH}) и поведение при переполнении (\texttt{QUEUE\_OVERFLOW}).
|
||||||
|
|
||||||
|
\item \textbf{networks} -- определение виртуальной сети \texttt{rabbitnet}, через которую все сервисы обмениваются данными. Используется стандартный сетевой драйвер \texttt{bridge}.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{lstlisting}[label={lst:}]
|
||||||
|
services:
|
||||||
|
rabbitmq:
|
||||||
|
image: rabbitmq:4.0-management
|
||||||
|
hostname: rabbitmq
|
||||||
|
container_name: rabbitmq
|
||||||
|
ports:
|
||||||
|
- "5672:5672"
|
||||||
|
- "15672:15672"
|
||||||
|
networks:
|
||||||
|
- rabbitnet
|
||||||
|
|
||||||
|
producer1:
|
||||||
|
container_name: producer1
|
||||||
|
build:
|
||||||
|
context: ./producer
|
||||||
|
depends_on:
|
||||||
|
- rabbitmq
|
||||||
|
- consumer
|
||||||
|
environment:
|
||||||
|
- PRODUCER_NAME=first
|
||||||
|
- PRODUCER_DELAY_MS=1000
|
||||||
|
networks:
|
||||||
|
- rabbitnet
|
||||||
|
|
||||||
|
producer2:
|
||||||
|
container_name: producer2
|
||||||
|
build:
|
||||||
|
context: ./producer
|
||||||
|
depends_on:
|
||||||
|
- rabbitmq
|
||||||
|
- consumer
|
||||||
|
environment:
|
||||||
|
- PRODUCER_NAME=second
|
||||||
|
- PRODUCER_DELAY_MS=1000
|
||||||
|
networks:
|
||||||
|
- rabbitnet
|
||||||
|
|
||||||
|
consumer:
|
||||||
|
container_name: consumer
|
||||||
|
build:
|
||||||
|
context: ./consumer
|
||||||
|
depends_on:
|
||||||
|
- rabbitmq
|
||||||
|
environment:
|
||||||
|
- CONSUMER_DELAY_MS=1000
|
||||||
|
- QUEUE_MAX_LENGTH=10
|
||||||
|
- QUEUE_OVERFLOW=reject-publish # drop-head, reject-publish
|
||||||
|
networks:
|
||||||
|
- rabbitnet
|
||||||
|
|
||||||
|
networks:
|
||||||
|
rabbitnet:
|
||||||
|
driver: bridge
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
\section{Результат работы}
|
||||||
|
|
||||||
|
Ниже представлены логи для 10 секунд работы контейнеров, в режиме \texttt{QUEUE\_OVERFLOW=drop-head}. Начиная с 25 строки видно, что получатель начинает получать сообщения только от первого отправителя, потому что сообщения второго просто удаляются.
|
||||||
|
\begin{lstlisting}[label={lst:}]
|
||||||
|
producer1 | [x] Sent 'Message from first #0'
|
||||||
|
producer1 | [x] Sent 'Message from first #1'
|
||||||
|
producer2 | [x] Sent 'Message from second #2'
|
||||||
|
consumer | [x] Received 'Message from second #1'
|
||||||
|
producer1 | [x] Sent 'Message from first #2'
|
||||||
|
producer2 | [x] Sent 'Message from second #3'
|
||||||
|
consumer | [x] Received 'Message from first #1'
|
||||||
|
producer1 | [x] Sent 'Message from first #3'
|
||||||
|
producer2 | [x] Sent 'Message from second #4'
|
||||||
|
consumer | [x] Received 'Message from second #2'
|
||||||
|
producer1 | [x] Sent 'Message from first #4'
|
||||||
|
producer2 | [x] Sent 'Message from second #5'
|
||||||
|
consumer | [x] Received 'Message from first #2'
|
||||||
|
producer1 | [x] Sent 'Message from first #5'
|
||||||
|
producer2 | [x] Sent 'Message from second #6'
|
||||||
|
consumer | [x] Received 'Message from second #3'
|
||||||
|
producer1 | [x] Sent 'Message from first #6'
|
||||||
|
producer2 | [x] Sent 'Message from second #7'
|
||||||
|
consumer | [x] Received 'Message from first #3'
|
||||||
|
producer1 | [x] Sent 'Message from first #7'
|
||||||
|
producer2 | [x] Sent 'Message from second #8'
|
||||||
|
consumer | [x] Received 'Message from second #4'
|
||||||
|
producer1 | [x] Sent 'Message from first #8'
|
||||||
|
producer2 | [x] Sent 'Message from second #9'
|
||||||
|
consumer | [x] Received 'Message from first #4'
|
||||||
|
producer1 | [x] Sent 'Message from first #9'
|
||||||
|
producer2 | [x] Sent 'Message from second #10'
|
||||||
|
consumer | [x] Received 'Message from first #5'
|
||||||
|
producer1 | [x] Sent 'Message from first #10'
|
||||||
|
producer2 | [x] Sent 'Message from second #11'
|
||||||
|
consumer | [x] Received 'Message from first #6'
|
||||||
|
producer1 | [x] Sent 'Message from first #11'
|
||||||
|
producer2 | [x] Sent 'Message from second #12'
|
||||||
|
consumer | [x] Received 'Message from first #7'
|
||||||
|
producer1 | [x] Sent 'Message from first #12'
|
||||||
|
producer2 | [x] Sent 'Message from second #13'
|
||||||
|
consumer | [x] Received 'Message from first #8'
|
||||||
|
producer1 | [x] Sent 'Message from first #13'
|
||||||
|
producer2 | [x] Sent 'Message from second #14'
|
||||||
|
consumer | [x] Received 'Message from first #9'
|
||||||
|
producer1 | [x] Sent 'Message from first #14'
|
||||||
|
producer2 | [x] Sent 'Message from second #15'
|
||||||
|
consumer | [x] Received 'Message from first #10'
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
Ниже представлены логи для 10 секунд работы контейнеров, в режиме \texttt{QUEUE\_OVERFLOW=reject-publish}. Начиная с 27 строки, второй отправитель выдаёт сообщение \texttt{Message was NOT confirmed!}, это означает, что он получает отказ от RabbitMQ и его сообщение не добавляется в очередь.
|
||||||
|
\begin{lstlisting}[label={lst:}]
|
||||||
|
producer1 | [x] Sent 'Message from first #0'
|
||||||
|
producer1 | [x] Sent 'Message from first #1'
|
||||||
|
consumer | [x] Received 'Message from second #1'
|
||||||
|
producer2 | [x] Sent 'Message from second #2'
|
||||||
|
producer1 | [x] Sent 'Message from first #2'
|
||||||
|
consumer | [x] Received 'Message from first #1'
|
||||||
|
producer2 | [x] Sent 'Message from second #3'
|
||||||
|
producer1 | [x] Sent 'Message from first #3'
|
||||||
|
consumer | [x] Received 'Message from second #2'
|
||||||
|
producer2 | [x] Sent 'Message from second #4'
|
||||||
|
producer1 | [x] Sent 'Message from first #4'
|
||||||
|
consumer | [x] Received 'Message from first #2'
|
||||||
|
producer2 | [x] Sent 'Message from second #5'
|
||||||
|
producer1 | [x] Sent 'Message from first #5'
|
||||||
|
consumer | [x] Received 'Message from second #3'
|
||||||
|
producer2 | [x] Sent 'Message from second #6'
|
||||||
|
producer1 | [x] Sent 'Message from first #6'
|
||||||
|
consumer | [x] Received 'Message from first #3'
|
||||||
|
producer2 | [x] Sent 'Message from second #7'
|
||||||
|
producer1 | [x] Sent 'Message from first #7'
|
||||||
|
producer2 | [x] Sent 'Message from second #8'
|
||||||
|
producer1 | [x] Sent 'Message from first #8'
|
||||||
|
consumer | [x] Received 'Message from second #4'
|
||||||
|
producer2 | [x] Sent 'Message from second #9'
|
||||||
|
producer1 | [x] Sent 'Message from first #9'
|
||||||
|
consumer | [x] Received 'Message from first #4'
|
||||||
|
producer2 | [!] Message was NOT confirmed!
|
||||||
|
producer1 | [x] Sent 'Message from first #10'
|
||||||
|
consumer | [x] Received 'Message from second #5'
|
||||||
|
producer2 | [!] Message was NOT confirmed!
|
||||||
|
producer1 | [x] Sent 'Message from first #11'
|
||||||
|
consumer | [x] Received 'Message from first #5'
|
||||||
|
producer2 | [!] Message was NOT confirmed!
|
||||||
|
producer1 | [x] Sent 'Message from first #12'
|
||||||
|
consumer | [x] Received 'Message from second #6'
|
||||||
|
producer2 | [!] Message was NOT confirmed!
|
||||||
|
producer1 | [x] Sent 'Message from first #13'
|
||||||
|
consumer | [x] Received 'Message from first #6'
|
||||||
|
producer1 | [x] Sent 'Message from first #14'
|
||||||
|
consumer | [x] Received 'Message from second #7'
|
||||||
|
producer2 | [!] Message was NOT confirmed!
|
||||||
|
producer1 | [x] Sent 'Message from first #15'
|
||||||
|
consumer | [x] Received 'Message from first #7'
|
||||||
|
producer2 | [!] Message was NOT confirmed!
|
||||||
|
producer1 | [x] Sent 'Message from first #16'
|
||||||
|
consumer | [x] Received 'Message from second #8'
|
||||||
|
producer2 | [!] Message was NOT confirmed!
|
||||||
|
producer1 | [x] Sent 'Message from first #17'
|
||||||
|
consumer | [x] Received 'Message from first #8'
|
||||||
|
producer2 | [!] Message was NOT confirmed!
|
||||||
|
consumer | [x] Received 'Message from second #9'
|
||||||
|
producer2 | [!] Message was NOT confirmed!
|
||||||
|
producer1 | [x] Sent 'Message from first #18'
|
||||||
|
consumer | [x] Received 'Message from first #9'
|
||||||
|
producer2 | [!] Message was NOT confirmed!
|
||||||
|
producer1 | [x] Sent 'Message from first #19'
|
||||||
|
consumer | [x] Received 'Message from first #10'
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
\end{document}
|
||||||
Reference in New Issue
Block a user