Ответ
TCP (Transmission Control Protocol) — это один из основных протоколов сетевой модели TCP/IP. Его главная задача — обеспечить надежную, упорядоченную и безошибочную доставку потока данных между двумя программами, запущенными на разных хостах в сети.
Ключевые характеристики TCP:
- Надежность (Reliability): Гарантирует, что данные будут доставлены. Если пакет теряется, TCP запрашивает его повторную отправку.
- Установка соединения (Connection-oriented): Перед обменом данными клиенту и серверу необходимо установить соединение через процесс "тройного рукопожатия" (three-way handshake: SYN, SYN-ACK, ACK).
- Упорядоченная доставка (Ordered Delivery): TCP гарантирует, что данные будут получены в том же порядке, в котором были отправлены.
- Контроль потока (Flow Control): Механизм, который не позволяет быстрому отправителю перегрузить медленного получателя.
Благодаря этим свойствам, TCP используется в большинстве популярных прикладных протоколов, где важна целостность данных: HTTP/HTTPS, FTP, SMTP, SSH, Telnet.
Примеры использования в Go:
В стандартной библиотеке Go (net) есть все необходимое для работы с TCP.
-
Простой TCP-сервер Сервер слушает порт, принимает входящие соединения и обрабатывает каждое в отдельной горутине.
package main import ( "fmt" "net" ) func handleConnection(conn net.Conn) { defer conn.Close() fmt.Printf("Accepted connection from %sn", conn.RemoteAddr()) // ... логика чтения/записи данных conn.Write([]byte("Hello from server!n")) } func main() { // Начинаем слушать порт 8080 по протоколу TCP ln, err := net.Listen("tcp", ":8080") if err != nil { panic(err) } defer ln.Close() fmt.Println("Server is listening on port 8080") for { // Ожидаем и принимаем новое соединение conn, err := ln.Accept() if err != nil { fmt.Println("Error accepting connection:", err) continue } // Обрабатываем соединение в новой горутине go handleConnection(conn) } } -
TCP-клиент Клиент устанавливает соединение с сервером, отправляет данные и читает ответ.
package main import ( "bufio" "fmt" "net" "time" ) func main() { // Устанавливаем соединение с таймаутом conn, err := net.DialTimeout("tcp", "localhost:8080", 5*time.Second) if err != nil { panic(err) } defer conn.Close() fmt.Println("Connected to server!") // Отправляем данные _, err = conn.Write([]byte("Hello, server!n")) if err != nil { panic(err) } // Читаем ответ от сервера message, _ := bufio.NewReader(conn).ReadString('n') fmt.Print("Message from server: " + message) }
В отличие от UDP, который является более быстрым, но ненадёжным протоколом без установки соединения, TCP выбирают тогда, когда потеря или нарушение порядка данных недопустимы.
Ответ 18+ 🔞
А, ну вот, TCP, блядь! Это ж тот самый протокол, который как занудная тётя с бухгалтерии — всё проверит, всё пересчитает, и если где-то копейка потерялась, будет орать до посинения, пока её не найдут. В рот меня чих-пых!
Короче, представь: ты хочешь отправить своему корегу на другой конец страны толстенный архив с фотками твоей поездки на шашлыки. И важно, чтобы всё дошло в идеальном порядке: сначала ты наливаешь, потом ты поджигаешь мангал, а потом уже горит каре. А не наоборот, ёпта! Вот TCP — это как ответственный курьер, который не просто кинет пакет в ящик, а лично вручит, получит роспись, и если что-то по дороге помялось — вернётся и привезёт новое, блядь.
Главные приколы этого протокола:
- Надёжность до одури (Reliability): Этот упырь не успокоится, пока каждый байт не долетит до цели. Пакет потерялся? Он его снова запросит, сука! Как назойливый коллектор, только для данных.
- Любовь с первого SYN'a (Connection-oriented): Прежде чем начать болтать, он устраивает целую церемонию «тройного рукопожатия»: «Привет, я SYN» — «Привет, я SYN-ACK» — «Ок, ACK». Только после этого можно скидывать нюдсы, то есть данные. Без этого — ни-ни, блядь.
- Порядок блюдёт (Ordered Delivery): Он гарантирует, что история будет рассказана по порядку: завязка, кульминация, потом уже пьяная драка в кустах. А не как в плохом монтаже — сразу разбитая морда, а потом «давай знакомиться».
- Контроль потока (Flow Control): Умная штука, которая не даст тебе, раздолбаю с гигабитным каналом, затопить своего друга, который сидит на модеме через спутник у бабушки в деревне. «Тише, — говорит, — едешь, придурок, он ещё предыдущий пакет разбирает!».
Именно поэтому на TCP ездит всё, что не может позволить себе потерь: твои мемы в браузере (HTTP/HTTPS), файлы на FTP, письма (SMTP) и даже когда ты подключаешься к серверу по SSH, чтобы что-то срочно починить, а вместо этого случайно rm -rf / набираешь. Вот это всё он, этот дотошный тип.
Как с этим жить в Go:
В Go, слава богу, всё уже прикручено в пакете net. Не надо, блядь, паять эти SYN-ACK'и руками.
-
TCP-сервер, который всех обслуживает Сервер, который слушает порт и на каждое новое соединение заводит отдельную горутину — как таджик-шашлычник на потоке.
package main import ( "fmt" "net" ) func handleConnection(conn net.Conn) { defer conn.Close() fmt.Printf("Accepted connection from %sn", conn.RemoteAddr()) // ... логика чтения/записи данных conn.Write([]byte("Hello from server!n")) } func main() { // Начинаем слушать порт 8080 по протоколу TCP ln, err := net.Listen("tcp", ":8080") if err != nil { panic(err) } defer ln.Close() fmt.Println("Server is listening on port 8080") for { // Ожидаем и принимаем новое соединение conn, err := ln.Accept() if err != nil { fmt.Println("Error accepting connection:", err) continue } // Обрабатываем соединение в новой горутине go handleConnection(conn) } } -
TCP-клиент, который стучится к нам Клиент, который подключается, шлёт привет и ждёт ответа, как пьяный друг под окном.
package main import ( "bufio" "fmt" "net" "time" ) func main() { // Устанавливаем соединение с таймаутом conn, err := net.DialTimeout("tcp", "localhost:8080", 5*time.Second) if err != nil { panic(err) } defer conn.Close() fmt.Println("Connected to server!") // Отправляем данные _, err = conn.Write([]byte("Hello, server!n")) if err != nil { panic(err) } // Читаем ответ от сервера message, _ := bufio.NewReader(conn).ReadString('n') fmt.Print("Message from server: " + message) }
А чем это лучше UDP? — спросишь ты. Да хуй его знает, чем лучше! UDP — это как крикнуть что-то в толпу: может, дойдёт, а может, и нет. Быстро, но ненадёжно. А TCP — это как заказное письмо с уведомлением: долго, муторно, зато ты точно знаешь, что адресат его получил и даже расписался, ёпта. Выбирай, что тебе важнее: скорость или чтобы всё долетело в целости и сохранности.