<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Ss on DevOps Way - Практические гайды</title>
    <link>https://devopsway.ru/tags/ss/</link>
    <description>Recent content in Ss on DevOps Way - Практические гайды</description>
    <image>
      <title>DevOps Way - Практические гайды</title>
      <url>https://devopsway.ru/images/devopsway-og.png</url>
      <link>https://devopsway.ru/images/devopsway-og.png</link>
    </image>
    <generator>Hugo -- 0.164.0</generator>
    <language>ru</language>
    <lastBuildDate>Thu, 23 Jul 2026 18:22:02 +0300</lastBuildDate>
    <atom:link href="https://devopsway.ru/tags/ss/feed.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Networking 20/80, уровень 3: TCP и UDP – анатомия соединения</title>
      <link>https://devopsway.ru/posts/networking-03-tcp-udp/</link>
      <pubDate>Thu, 23 Jul 2026 12:00:00 +0300</pubDate>
      <guid>https://devopsway.ru/posts/networking-03-tcp-udp/</guid>
      <description>Четвёртый уровень: чем TCP отличается от UDP, трёхстороннее рукопожатие и состояния соединения, порты, ss и tcpdump, TIME_WAIT. Почему &amp;#39;Connection refused&amp;#39; и &amp;#39;Connection timeout&amp;#39; – это разные диагнозы. Три подвоха с собеса и чеклист &amp;#39;почему не подключается&amp;#39;.</description>
      <content:encoded><![CDATA[<p>Четвёртый из семи уровней. Адреса и имена уже пройдены – данные знают, куда ехать. Теперь про то, КАК они едут: TCP с гарантией доставки против UDP без гарантий, трёхстороннее рукопожатие, состояния соединения и два самых частых диагноза на дежурстве, которые новички путают – &quot;refused&quot; и &quot;timeout&quot;.</p>
<blockquote>
<p>&quot;Connection refused&quot; и &quot;Connection timeout&quot; – две самых частых ошибки в DevOps. Они означают совершенно разные вещи, и различие – в TCP.&quot;</p>
</blockquote>
<hr>
<h2 id="откуда-это-пошло">Откуда это пошло</h2>
<p><strong>1974 – Vint Cerf и Bob Kahn публикуют TCP</strong> (Transmission Control Protocol). Проблема: IP-пакеты могут теряться, дублироваться, приходить не в том порядке. TCP решает: надёжная, упорядоченная доставка поверх ненадёжной сети.</p>
<p><strong>1980 – UDP</strong> (User Datagram Protocol, RFC 768). Иногда надёжность не нужна, а скорость – критична. DNS-запрос: один вопрос – один ответ, зачем рукопожатие? Видеозвонок: лучше пропустить кадр, чем ждать повторной передачи.</p>
<p><strong>Аналогия:</strong> TCP – заказное письмо с уведомлением о вручении. UDP – открытка без обратного адреса.</p>
<hr>
<h2 id="tcp-vs-udp--фундаментальное-различие">TCP vs UDP – фундаментальное различие</h2>
<table>
	<thead>
			<tr>
					<th></th>
					<th>TCP</th>
					<th>UDP</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><strong>Соединение</strong></td>
					<td>Да (рукопожатие, handshake)</td>
					<td>Нет (без установления, fire-and-forget)</td>
			</tr>
			<tr>
					<td><strong>Надёжность</strong></td>
					<td>Гарантированная доставка</td>
					<td>Нет гарантий</td>
			</tr>
			<tr>
					<td><strong>Порядок</strong></td>
					<td>Гарантирован</td>
					<td>Не гарантирован</td>
			</tr>
			<tr>
					<td><strong>Контроль потока</strong></td>
					<td>Да (flow control, congestion)</td>
					<td>Нет</td>
			</tr>
			<tr>
					<td><strong>Накладные расходы (overhead)</strong></td>
					<td>Высокий (20+ байт заголовок)</td>
					<td>Низкий (8 байт)</td>
			</tr>
			<tr>
					<td><strong>Примеры</strong></td>
					<td>HTTP, SSH, SMTP, PostgreSQL</td>
					<td>DNS, NTP, DHCP, видео, игры</td>
			</tr>
			<tr>
					<td><strong>Для DevOps</strong></td>
					<td>95% трафика</td>
					<td>DNS-запросы, мониторинг (StatsD)</td>
			</tr>
	</tbody>
</table>
<hr>
<h2 id="трёхстороннее-рукопожатие-tcp-handshake">Трёхстороннее рукопожатие (TCP handshake)</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">Клиент (curl)                          Сервер (nginx:8080)
</span></span><span class="line"><span class="cl">     │                                       │
</span></span><span class="line"><span class="cl">     │──── SYN (seq=100) ──────────────────→│  1. &#34;Привет, хочу подключиться&#34;
</span></span><span class="line"><span class="cl">     │                                       │
</span></span><span class="line"><span class="cl">     │←─── SYN-ACK (seq=300, ack=101) ─────│  2. &#34;ОК, я тоже готов&#34;
</span></span><span class="line"><span class="cl">     │                                       │
</span></span><span class="line"><span class="cl">     │──── ACK (seq=101, ack=301) ──────────→│  3. &#34;Подтверждаю, начинаем&#34;
</span></span><span class="line"><span class="cl">     │                                       │
</span></span><span class="line"><span class="cl">     │         ═══ СОЕДИНЕНИЕ УСТАНОВЛЕНО ═══│
</span></span><span class="line"><span class="cl">     │                                       │
</span></span><span class="line"><span class="cl">     │──── DATA: &#34;GET /health HTTP/1.1&#34; ───→│  4. Отправка данных
</span></span><span class="line"><span class="cl">     │                                       │
</span></span></code></pre></div><h3 id="что-происходит-при-ошибках">Что происходит при ошибках</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">&#34;Connection refused&#34; (мгновенная ошибка):
</span></span><span class="line"><span class="cl">     │──── SYN ──────────────→│
</span></span><span class="line"><span class="cl">     │←─── RST ──────────────│  Сервер АКТИВНО отказывает:
</span></span><span class="line"><span class="cl">     │                         │  - Порт не слушается
</span></span><span class="line"><span class="cl">     │                         │  - файрвол с REJECT
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">&#34;Connection timeout&#34; (ожидание 30+ секунд):
</span></span><span class="line"><span class="cl">     │──── SYN ──────────────→│ ... тишина ...
</span></span><span class="line"><span class="cl">     │──── SYN (retry 1) ───→│ ... тишина ...
</span></span><span class="line"><span class="cl">     │──── SYN (retry 2) ───→│ ... тишина ...
</span></span><span class="line"><span class="cl">     │──── TIMEOUT ──────────│  Пакет пропал:
</span></span><span class="line"><span class="cl">     │                         │  - файрвол с DROP (не REJECT)
</span></span><span class="line"><span class="cl">     │                         │  - Хост выключен
</span></span><span class="line"><span class="cl">     │                         │  - Нет маршрута
</span></span></code></pre></div><blockquote>
<p><strong>20/80 для диагностики (troubleshooting):</strong></p>
<ul>
<li><strong>Connection refused</strong> → сервис не запущен ИЛИ слушает на другом порту/интерфейсе</li>
<li><strong>Connection timeout</strong> → файрвол DROP, хост недоступен, неправильный IP/порт</li>
</ul>
</blockquote>
<hr>
<h2 id="порты--адреса-для-приложений">Порты – адреса для приложений</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">IP-адрес = адрес компьютера (как адрес дома)
</span></span><span class="line"><span class="cl">Порт = номер квартиры (какое приложение)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Полный адрес: 10.0.0.5:8080
</span></span><span class="line"><span class="cl">              └─IP────┘ └порт┘
</span></span></code></pre></div><h3 id="порты-которые-стоит-знать-наизусть">Порты, которые стоит знать наизусть</h3>
<p>Строго говоря, &quot;системные&quot; порты (well-known) – это только 0–1023 (ниже: SSH, DNS, HTTP, HTTPS). Остальные – зарегистрированные пользовательские, но в DevOps встречаются постоянно:</p>
<table>
	<thead>
			<tr>
					<th>Порт</th>
					<th>Протокол</th>
					<th>Сервис</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>22</td>
					<td>TCP</td>
					<td>SSH</td>
			</tr>
			<tr>
					<td>53</td>
					<td>TCP/UDP</td>
					<td>DNS</td>
			</tr>
			<tr>
					<td>80</td>
					<td>TCP</td>
					<td>HTTP</td>
			</tr>
			<tr>
					<td>443</td>
					<td>TCP</td>
					<td>HTTPS</td>
			</tr>
			<tr>
					<td>5432</td>
					<td>TCP</td>
					<td>PostgreSQL</td>
			</tr>
			<tr>
					<td>6379</td>
					<td>TCP</td>
					<td>Redis</td>
			</tr>
			<tr>
					<td>9090</td>
					<td>TCP</td>
					<td>Prometheus</td>
			</tr>
			<tr>
					<td>3000</td>
					<td>TCP</td>
					<td>Grafana</td>
			</tr>
			<tr>
					<td>8080</td>
					<td>TCP</td>
					<td>HTTP (альтернативный)</td>
			</tr>
			<tr>
					<td>9000</td>
					<td>TCP</td>
					<td>ClickHouse (native)</td>
			</tr>
			<tr>
					<td>8123</td>
					<td>TCP</td>
					<td>ClickHouse (HTTP)</td>
			</tr>
			<tr>
					<td>2379</td>
					<td>TCP</td>
					<td>etcd (K8s)</td>
			</tr>
			<tr>
					<td>6443</td>
					<td>TCP</td>
					<td>K8s API server</td>
			</tr>
			<tr>
					<td>10250</td>
					<td>TCP</td>
					<td>kubelet</td>
			</tr>
	</tbody>
</table>
<h3 id="эфемерные-порты-ephemeral-3276860999">Эфемерные порты (ephemeral, 32768–60999)</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Клиент использует случайный порт:</span>
</span></span><span class="line"><span class="cl">curl http://api:8080
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># В TCP-пакете:</span>
</span></span><span class="line"><span class="cl"><span class="c1"># src_port = 54321 (эфемерный – случайный)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># dst_port = 8080  (системный – целевой)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Диапазон эфемерных портов:</span>
</span></span><span class="line"><span class="cl">cat /proc/sys/net/ipv4/ip_local_port_range
</span></span><span class="line"><span class="cl"><span class="c1"># 32768   60999</span>
</span></span></code></pre></div><hr>
<h2 id="сокет--и-почему-ss-так-называется">Сокет – и почему <code>ss</code> так называется</h2>
<p><code>ss</code> расшифровывается как <strong>socket statistics</strong>. А что такое сокет – ещё помнишь? В сетях сокет – это конечная точка соединения, пара <code>IP:порт</code>.</p>
<p>Слушающий сокет (listening) один: <code>0.0.0.0:8080</code>. А вот установленное соединение задаётся уже <strong>четвёркой</strong> (4-tuple):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(IP:порт клиента)  ↔  (IP:порт сервера)
</span></span><span class="line"><span class="cl"> 10.0.0.10:54321   ↔   10.0.0.5:8080
</span></span></code></pre></div><p>Отсюда то, что обычно и спрашивают:</p>
<ul>
<li><strong>Почему nginx на одном порту 8080 держит тысячи соединений?</strong> Порт сервера один, но каждый клиент приходит со своим <code>src IP:порт</code> – каждая четвёрка уникальна.</li>
<li><strong>Почему на клиенте кончаются порты</strong> (<code>Cannot assign requested address</code>)? При массе исходящих к одному <code>dst</code> уникальным остаётся только <code>src port</code>, а их всего ~28000.</li>
<li>Колонки <code>Local Address:Port</code> и <code>Peer Address:Port</code> в <code>ss -tnp</code> (ниже) – это и есть две половины четвёрки.</li>
</ul>
<p><strong>И не путать – сокетов много:</strong></p>
<ul>
<li><strong>Unix-сокет</strong> (Unix domain socket) – не <code>IP:порт</code>, а файл: <code>/run/postgresql/.s.PGSQL.5432</code>, <code>/run/docker.sock</code>. Тот же PostgreSQL слушает и сетевой сокет <code>IP:5432</code>, и локальный файл-сокет (<code>ss -x</code> покажет их).</li>
<li><strong>Процессорный сокет</strong> (CPU socket из <code>lscpu</code>) – это железо, разъём под процессор.</li>
<li><strong>Вызов <code>socket()</code></strong> из Berkeley API – программистская абстракция создания сокета; под капот приложения нам не надо.</li>
</ul>
<hr>
<h2 id="ss--современная-замена-netstat">ss – современная замена netstat</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Все слушающие TCP-порты:</span>
</span></span><span class="line"><span class="cl">ss -tlnp
</span></span><span class="line"><span class="cl"><span class="c1"># State  Local Address:Port  Process</span>
</span></span><span class="line"><span class="cl"><span class="c1"># LISTEN 0.0.0.0:22          sshd</span>
</span></span><span class="line"><span class="cl"><span class="c1"># LISTEN 0.0.0.0:8080        nginx</span>
</span></span><span class="line"><span class="cl"><span class="c1"># LISTEN 127.0.0.1:5432      postgres    ← только localhost!</span>
</span></span><span class="line"><span class="cl"><span class="c1"># LISTEN [::]:80              nginx       ← IPv4 + IPv6</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Расшифровка флагов:</span>
</span></span><span class="line"><span class="cl"><span class="c1"># -t = TCP</span>
</span></span><span class="line"><span class="cl"><span class="c1"># -l = LISTEN (слушающие)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># -n = числовые порты (не резолвить имена)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># -p = показать процесс (нужен root)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Все активные TCP-соединения:</span>
</span></span><span class="line"><span class="cl">ss -tnp
</span></span><span class="line"><span class="cl"><span class="c1"># State       Local Address:Port    Peer Address:Port    Process</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ESTAB       10.0.0.5:8080        10.0.0.10:54321      nginx</span>
</span></span><span class="line"><span class="cl"><span class="c1"># TIME-WAIT   10.0.0.5:8080        10.0.0.11:54322</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># UDP:</span>
</span></span><span class="line"><span class="cl">ss -ulnp
</span></span><span class="line"><span class="cl"><span class="c1"># LISTEN  0.0.0.0:53    coredns</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Статистика:</span>
</span></span><span class="line"><span class="cl">ss -s
</span></span><span class="line"><span class="cl"><span class="c1"># TCP: 45 (estab 12, closed 5, timewait 8)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Фильтр по порту:</span>
</span></span><span class="line"><span class="cl">ss -tnp dst :8080
</span></span><span class="line"><span class="cl">ss -tnp src :22
</span></span></code></pre></div><blockquote>
<p><strong>netstat vs ss:</strong> <code>netstat</code> – пакет <code>net-tools</code> (устаревший, deprecated). <code>ss</code> – пакет <code>iproute2</code> (современный, быстрее). На собесе используй <code>ss</code>.</p>
</blockquote>
<hr>
<h2 id="состояния-tcp-соединения">Состояния TCP-соединения</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">             ┌─────────┐
</span></span><span class="line"><span class="cl">             │  CLOSED  │
</span></span><span class="line"><span class="cl">             └────┬─────┘
</span></span><span class="line"><span class="cl">        SYN sent  │  SYN received
</span></span><span class="line"><span class="cl">             ┌────▼─────┐
</span></span><span class="line"><span class="cl">             │ SYN_SENT │ (клиент ждёт SYN-ACK)
</span></span><span class="line"><span class="cl">             └────┬─────┘
</span></span><span class="line"><span class="cl">          SYN-ACK │
</span></span><span class="line"><span class="cl">             ┌────▼──────┐
</span></span><span class="line"><span class="cl">             │ESTABLISHED │ ← рабочее состояние
</span></span><span class="line"><span class="cl">             └────┬──────┘
</span></span><span class="line"><span class="cl">           FIN    │
</span></span><span class="line"><span class="cl">             ┌────▼──────┐
</span></span><span class="line"><span class="cl">             │ FIN_WAIT  │ (закрытие инициировано)
</span></span><span class="line"><span class="cl">             └────┬──────┘
</span></span><span class="line"><span class="cl">                  │
</span></span><span class="line"><span class="cl">             ┌────▼──────┐
</span></span><span class="line"><span class="cl">             │ TIME_WAIT │ ← ожидание 2×MSL (60 сек)
</span></span><span class="line"><span class="cl">             └────┬──────┘
</span></span><span class="line"><span class="cl">                  │
</span></span><span class="line"><span class="cl">             ┌────▼─────┐
</span></span><span class="line"><span class="cl">             │  CLOSED  │
</span></span><span class="line"><span class="cl">             └──────────┘
</span></span></code></pre></div><h3 id="time_wait--частая-проблема">TIME_WAIT – частая проблема</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Много TIME_WAIT = нормально для высоконагруженных серверов</span>
</span></span><span class="line"><span class="cl">ss -tn state time-wait <span class="p">|</span> wc -l
</span></span><span class="line"><span class="cl"><span class="c1"># 1500 ← если &lt; 10000 – ОК</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Проблема: если &gt; 28000 (лимит ephemeral портов)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># → &#34;Cannot assign requested address&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Решение (в /etc/sysctl.conf):</span>
</span></span><span class="line"><span class="cl">net.ipv4.tcp_tw_reuse <span class="o">=</span> <span class="m">1</span>          <span class="c1"># переиспользовать TIME_WAIT сокеты</span>
</span></span><span class="line"><span class="cl">net.core.somaxconn <span class="o">=</span> <span class="m">65535</span>         <span class="c1"># увеличить очередь соединений (backlog)</span>
</span></span></code></pre></div><hr>
<h2 id="tcpdump--рентген-для-сетевого-трафика">tcpdump – &quot;рентген&quot; для сетевого трафика</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Весь трафик на интерфейсе eth0:</span>
</span></span><span class="line"><span class="cl">sudo tcpdump -i eth0
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Только TCP на порт 8080:</span>
</span></span><span class="line"><span class="cl">sudo tcpdump -i eth0 tcp port <span class="m">8080</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># TCP-рукопожатие (SYN, SYN-ACK, ACK):</span>
</span></span><span class="line"><span class="cl">sudo tcpdump -i eth0 <span class="s1">&#39;tcp[tcpflags] &amp; (tcp-syn|tcp-ack) != 0&#39;</span> -c <span class="m">10</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># DNS-запросы:</span>
</span></span><span class="line"><span class="cl">sudo tcpdump -i eth0 udp port <span class="m">53</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># HTTP-запросы (ASCII):</span>
</span></span><span class="line"><span class="cl">sudo tcpdump -i eth0 -A tcp port <span class="m">80</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Сохранить в файл для анализа в Wireshark:</span>
</span></span><span class="line"><span class="cl">sudo tcpdump -i eth0 -w capture.pcap tcp port <span class="m">8080</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Фильтр по IP:</span>
</span></span><span class="line"><span class="cl">sudo tcpdump -i eth0 host 10.0.0.5
</span></span><span class="line"><span class="cl">sudo tcpdump -i eth0 src 10.0.0.5 and dst port <span class="m">8080</span>
</span></span></code></pre></div><h3 id="чтение-вывода-tcpdump">Чтение вывода tcpdump</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">10:05:23.456789 IP 10.0.0.5.54321 &gt; 10.0.0.10.8080: Flags [S], seq 12345
</span></span><span class="line"><span class="cl">│               │  └── src:port  ┘   └── dst:port ┘  └─ SYN ┘  └── seq ┘
</span></span><span class="line"><span class="cl">│               └── протокол (IP)
</span></span><span class="line"><span class="cl">└── timestamp
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Flags:
</span></span><span class="line"><span class="cl">[S]     = SYN (начало соединения)
</span></span><span class="line"><span class="cl">[S.]    = SYN-ACK (ответ на SYN)
</span></span><span class="line"><span class="cl">[.]     = ACK
</span></span><span class="line"><span class="cl">[P.]    = PUSH-ACK (данные)
</span></span><span class="line"><span class="cl">[F.]    = FIN-ACK (закрытие)
</span></span><span class="line"><span class="cl">[R.]    = RST (сброс – &#34;connection refused&#34;)
</span></span></code></pre></div><hr>
<h2 id="практика-почему-не-подключается">Практика: &quot;Почему не подключается?&quot;</h2>
<h3 id="чеклист-диагностики-от-l1-к-l7">Чеклист диагностики (от L1 к L7)</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 1. Сеть доступна? (L3)</span>
</span></span><span class="line"><span class="cl">ping 10.0.0.10
</span></span><span class="line"><span class="cl"><span class="c1"># Если timeout → проблема маршрутизации или firewall</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 2. Порт открыт? (L4)</span>
</span></span><span class="line"><span class="cl">ss -tlnp <span class="p">|</span> grep <span class="m">8080</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Если пусто → сервис не слушает</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 3. TCP-соединение устанавливается?</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Быстрая проверка:</span>
</span></span><span class="line"><span class="cl">nc -zv 10.0.0.10 <span class="m">8080</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Connection to 10.0.0.10 8080 port [tcp/*] succeeded!  ← ОК</span>
</span></span><span class="line"><span class="cl"><span class="c1"># nc: connect to 10.0.0.10 port 8080: Connection refused  ← порт закрыт</span>
</span></span><span class="line"><span class="cl"><span class="c1"># nc: connect to 10.0.0.10 port 8080: Connection timed out  ← firewall DROP</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 4. Что на проводе?</span>
</span></span><span class="line"><span class="cl">sudo tcpdump -i eth0 host 10.0.0.10 and port <span class="m">8080</span> -c <span class="m">5</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 5. Приложение отвечает? (L7)</span>
</span></span><span class="line"><span class="cl">curl -v http://10.0.0.10:8080/health
</span></span></code></pre></div><hr>
<h2 id="подвохи-для-собеса">Подвохи для собеса</h2>
<h3 id="подвох-1-чем-connection-refused-отличается-от-connection-timeout">Подвох 1: &quot;Чем &quot;Connection refused&quot; отличается от &quot;Connection timeout&quot;?&quot;</h3>
<p><strong>Ответ через TCP:</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">Connection refused:
</span></span><span class="line"><span class="cl">  Клиент отправил SYN → получил RST (reset)
</span></span><span class="line"><span class="cl">  Значит: пакет ДОШЁЛ до хоста, но порт НЕ слушает
</span></span><span class="line"><span class="cl">  Время: мгновенно (&lt; 1мс)
</span></span><span class="line"><span class="cl">  Причины: сервис не запущен, слушает другой порт, firewall REJECT
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Connection timeout:
</span></span><span class="line"><span class="cl">  Клиент отправил SYN → тишина → retry → тишина → timeout
</span></span><span class="line"><span class="cl">  Значит: пакет НЕ ДОШЁЛ или ответ потерялся
</span></span><span class="line"><span class="cl">  Время: 30–120 секунд (зависит от tcp_syn_retries)
</span></span><span class="line"><span class="cl">  Причины: firewall DROP, хост выключен, неправильный IP, нет маршрута
</span></span></code></pre></div><p><strong>На собесе:</strong> &quot;Refused – RST пришёл, хост жив, но порт закрыт. Timeout – ответа нет, пакет не дошёл или заблокирован. Разница принципиальна: refused = проблема на хосте (сервис), timeout = проблема в сети (маршрутизация/firewall).&quot;</p>
<hr>
<h3 id="подвох-2-зачем-нужен-трёхстороннее-рукопожатие-почему-не-двустороннее">Подвох 2: &quot;Зачем нужен трёхстороннее рукопожатие? Почему не двустороннее?&quot;</h3>
<p><strong>Ответ:</strong></p>
<p>Двустороннее: SYN → SYN-ACK. Проблема: клиент отправил SYN, но не получил SYN-ACK (потерялся). Клиент думает, что нет соединения. Сервер думает, что есть. <strong>Рассинхронизация.</strong></p>
<p>Трёхстороннее: SYN → SYN-ACK → ACK. Обе стороны подтвердили, что обе стороны получили подтверждение.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">Двустороннее (сломанное):
</span></span><span class="line"><span class="cl">  Клиент → SYN → Сервер       ✓ Сервер знает о клиенте
</span></span><span class="line"><span class="cl">  Клиент ← SYN-ACK ← Сервер   ✓ Клиент знает о сервере
</span></span><span class="line"><span class="cl">  Но сервер НЕ знает, получил ли клиент SYN-ACK!
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Трёхстороннее (рабочее):
</span></span><span class="line"><span class="cl">  Клиент → SYN → Сервер       ✓ Сервер знает о клиенте
</span></span><span class="line"><span class="cl">  Клиент ← SYN-ACK ← Сервер   ✓ Клиент знает о сервере
</span></span><span class="line"><span class="cl">  Клиент → ACK → Сервер       ✓ Сервер знает, что клиент получил
</span></span></code></pre></div><p><strong>На собесе:</strong> &quot;Трёхстороннее рукопожатие гарантирует, что обе стороны синхронизировали начальные порядковые номера (sequence numbers) и обе подтвердили готовность. Без третьего ACK – полуоткрытые соединения (half-open) и утечка ресурсов на сервере (атака SYN-флуд эксплуатирует именно это).&quot;</p>
<hr>
<h3 id="подвох-3-когда-udp-лучше-tcp">Подвох 3: &quot;Когда UDP лучше TCP?&quot;</h3>
<p><strong>Ответ:</strong></p>
<ol>
<li><strong>DNS</strong> – один запрос, один ответ, &lt; 512 байт. TCP overhead (handshake) больше самих данных</li>
<li><strong>Мониторинг</strong> (StatsD, syslog) – потеря одной метрики некритична, а задержка TCP – критична</li>
<li><strong>Видео/аудио</strong> – лучше пропустить кадр, чем ждать повторной передачи (TCP retransmit = задержка)</li>
<li><strong>Игры</strong> – латентность &gt; надёжность</li>
<li><strong>QUIC/HTTP3</strong> – Google построил надёжный протокол ПОВЕРХ UDP (вместо TCP), потому что TCP-рукопожатие = лишний круговой обмен (RTT)</li>
</ol>
<p><strong>На собесе:</strong> &quot;UDP выбирают, когда потеря отдельных пакетов допустима, а задержка – нет. Или когда обмен запрос-ответ (request-response) укладывается в один пакет (DNS). Современный тренд – QUIC: надёжность TCP + скорость UDP, потому что рукопожатие совмещено с TLS-рукопожатием (handshake).&quot;</p>
<hr>
<h2 id="код-челлендж">Код-челлендж</h2>
<p><strong>Задача:</strong> на любой Linux-машине выполни диагностику и ответь:</p>
<ol>
<li>Какие порты слушает nginx? (<code>ss -tlnp</code>)</li>
<li>Сколько активных TCP-соединений к PostgreSQL (порт 5432)?</li>
<li>Перехвати DNS-запрос с помощью tcpdump при выполнении <code>dig google.com</code></li>
<li>Проверь, доступен ли порт 6443 (K8s API) на master-ноде</li>
</ol>
<details>
<summary>Решение</summary>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 1. Порты nginx:</span>
</span></span><span class="line"><span class="cl">ss -tlnp <span class="p">|</span> grep nginx
</span></span><span class="line"><span class="cl"><span class="c1"># LISTEN 0.0.0.0:80  nginx</span>
</span></span><span class="line"><span class="cl"><span class="c1"># LISTEN 0.0.0.0:443 nginx</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 2. Активные соединения к PostgreSQL (на сервере БД порт 5432 – локальный):</span>
</span></span><span class="line"><span class="cl">ss -tnp src :5432 <span class="p">|</span> grep ESTAB <span class="p">|</span> wc -l
</span></span><span class="line"><span class="cl"><span class="c1"># С клиента, который сам ходит в БД, наоборот: dst :5432</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 3. Перехват DNS:</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Терминал 1:</span>
</span></span><span class="line"><span class="cl">sudo tcpdump -i eth0 udp port <span class="m">53</span> -c <span class="m">4</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Терминал 2:</span>
</span></span><span class="line"><span class="cl">dig google.com
</span></span><span class="line"><span class="cl"><span class="c1"># Увидишь: запрос (Query) и ответ (Response)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 4. K8s API порт:</span>
</span></span><span class="line"><span class="cl">nc -zv &lt;master-ip&gt; <span class="m">6443</span> -w <span class="m">3</span>
</span></span><span class="line"><span class="cl"><span class="c1"># succeeded! → доступен</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Connection timed out → firewall блокирует</span>
</span></span></code></pre></div></details>
<hr>
<h2 id="дальше--уровень-4">Дальше → Уровень 4</h2>
<p>Ты понимаешь TCP: рукопожатие, порты, состояния, умеешь диагностировать <code>ss</code> и <code>tcpdump</code>. Ты знаешь, ПОЧЕМУ &quot;Connection refused&quot; отличается от &quot;timeout&quot;.</p>
<p>Но TCP – транспорт. Данные, которые по нему передаются – это HTTP: запросы, ответы, заголовки, статус-коды. А с 2015 года почти весь HTTP – зашифрован TLS (HTTPS). Когда ты видишь <code>502 Bad Gateway</code> или <code>ERR_CERT_DATE_INVALID</code> – это проблемы на уровне HTTP/TLS.</p>
<p><strong>→ Уровень 4: HTTP и TLS – протокол, на котором всё держится</strong></p>
]]></content:encoded>
    </item>
  </channel>
</rss>
