Обмен по TCP в Go
После установки TCP-связи обмен идет в обе стороны по одному каналу. Сервер может сначала дождаться байтов от клиента, разобрать их как текст и записать ответ в тот же объект соединения, не открывая новый порт.
Чтение не обязано заполнить весь буфер: за один вызов приходит столько байтов, сколько клиент уже успел отправить. Ответ собирают из литерала и прочитанного куска; длину при записи и печати берут из числа, которое вернул прием.
Клиент шлет строку, сервер отвечает
префиксом "echo: " и тем же текстом:
package main
import (
"fmt"
"log"
"net"
"time"
)
func replyServer(addr string) {
ln, err := net.Listen("tcp", addr)
if err != nil {
log.Fatal(err)
}
defer ln.Close()
conn, err := ln.Accept()
if err != nil {
log.Fatal(err)
}
defer conn.Close()
buf := make([]byte, 256)
n, err := conn.Read(buf)
if err != nil {
log.Fatal(err)
}
text := string(buf[:n])
out := "echo: " + text
_, err = conn.Write([]byte(out))
if err != nil {
log.Fatal(err)
}
}
func main() {
addr := "127.0.0.1:9090"
go replyServer(addr)
time.Sleep(10 * time.Millisecond)
conn, err := net.Dial("tcp", addr)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
_, err = conn.Write([]byte("ping"))
if err != nil {
log.Fatal(err)
}
buf := make([]byte, 256)
n, err := conn.Read(buf)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(buf[:n]))
}
На экране клиента "echo: ping".
Сервер прочитал три байта, собрал ответ
и отправил его до закрытия соединения.
Если клиент шлет более длинную фразу, тот же порядок шагов сохраняется:
package main
import (
"fmt"
"log"
"net"
"time"
)
func replyServer(addr string) {
ln, err := net.Listen("tcp", addr)
if err != nil {
log.Fatal(err)
}
defer ln.Close()
conn, err := ln.Accept()
if err != nil {
log.Fatal(err)
}
defer conn.Close()
buf := make([]byte, 256)
n, err := conn.Read(buf)
if err != nil {
log.Fatal(err)
}
out := "echo: " + string(buf[:n])
_, err = conn.Write([]byte(out))
if err != nil {
log.Fatal(err)
}
}
func main() {
addr := "127.0.0.1:9090"
go replyServer(addr)
time.Sleep(10 * time.Millisecond)
conn, err := net.Dial("tcp", addr)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
_, err = conn.Write([]byte("long message"))
if err != nil {
log.Fatal(err)
}
buf := make([]byte, 256)
n, err := conn.Read(buf)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(buf[:n]))
}
Дано сообщение клиента:
clientLine := "ask"
На сервере после чтения в буфер 256
байт отправьте клиенту строку
"reply: ask", если в буфер
попало ровно clientLine.
Дан адрес:
addr := "127.0.0.1:9090"
Клиент отправляет "go" на
addr и ждет ответ; сервер
возвращает "echo: go". Опишите
порядок вызовов чтения и записи на
стороне сервера.
Скажите, почему ответ пишут в conn,
а не в ln, после того как клиент
уже подключился.