8. Сетевое программирование #
Сетевое программирование в Go строится на богатой стандартной библиотеке и поддерживает различные протоколы, такие как TCP, UDP, HTTP и современные технологии вроде gRPC и WebSocket.
8.1 Основы работы с TCP и UDP #
TCP (Transmission Control Protocol) #
Для работы с TCP используются функции пакета net
.
Сервер TCP:
package main
import (
"bufio"
"fmt"
"net"
"strings"
)
func handleConnection(conn net.Conn) {
defer conn.Close()
reader := bufio.NewReader(conn)
for {
message, _ := reader.ReadString('\n')
fmt.Print("Сообщение от клиента: ", message)
if strings.TrimSpace(message) == "exit" {
fmt.Println("Клиент отключился.")
break
}
conn.Write([]byte("Принято: " + message))
}
}
func main() {
listener, _ := net.Listen("tcp", ":8080")
defer listener.Close()
fmt.Println("TCP сервер запущен на порту 8080")
for {
conn, _ := listener.Accept()
go handleConnection(conn)
}
}
Клиент TCP:
package main
import (
"bufio"
"fmt"
"net"
"os"
)
func main() {
conn, _ := net.Dial("tcp", "localhost:8080")
defer conn.Close()
for {
fmt.Print("Введите сообщение: ")
input := bufio.NewReader(os.Stdin)
message, _ := input.ReadString('\n')
conn.Write([]byte(message))
reply, _ := bufio.NewReader(conn).ReadString('\n')
fmt.Print("Ответ сервера: ", reply)
}
}
UDP (User Datagram Protocol) #
Сервер UDP:
package main
import (
"fmt"
"net"
)
func main() {
addr, _ := net.ResolveUDPAddr("udp", ":8080")
conn, _ := net.ListenUDP("udp", addr)
defer conn.Close()
fmt.Println("UDP сервер запущен на порту 8080")
buffer := make([]byte, 1024)
for {
n, clientAddr, _ := conn.ReadFromUDP(buffer)
fmt.Printf("Сообщение от %s: %s\n", clientAddr, string(buffer[:n]))
conn.WriteToUDP([]byte("Принято\n"), clientAddr)
}
}
Клиент UDP:
package main
import (
"fmt"
"net"
)
func main() {
serverAddr, _ := net.ResolveUDPAddr("udp", "localhost:8080")
conn, _ := net.DialUDP("udp", nil, serverAddr)
defer conn.Close()
message := []byte("Привет UDP!")
conn.Write(message)
buffer := make([]byte, 1024)
n, _, _ := conn.ReadFromUDP(buffer)
fmt.Println("Ответ сервера:", string(buffer[:n]))
}
8.2 HTTP-серверы и клиенты #
Для работы с HTTP используется пакет net/http
.
HTTP-сервер: #
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Привет, Go HTTP!")
}
func main() {
http.HandleFunc("/", handler)
fmt.Println("HTTP сервер запущен на :8080")
http.ListenAndServe(":8080", nil)
}
HTTP-клиент: #
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
resp, _ := http.Get("http://example.com")
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}
8.3 gRPC: основы и примеры #
Для работы с gRPC используется пакет google.golang.org/grpc
.
Шаги работы с gRPC: #
- Создайте
.proto
файл для описания сервиса. - Сгенерируйте сервер и клиент с помощью
protoc
. - Реализуйте сервер на Go.
Пример service.proto
:
syntax = "proto3";
package example;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloResponse);
}
message HelloRequest {
string name = 1;
}
message HelloResponse {
string message = 1;
}
Сервер gRPC:
package main
import (
"context"
"fmt"
"net"
pb "example/proto" // Сгенерированный код
"google.golang.org/grpc"
)
type server struct {
pb.UnimplementedGreeterServer
}
func (s *server) SayHello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloResponse, error) {
return &pb.HelloResponse{Message: "Привет, " + req.Name}, nil
}
func main() {
listener, _ := net.Listen("tcp", ":50051")
grpcServer := grpc.NewServer()
pb.RegisterGreeterServer(grpcServer, &server{})
fmt.Println("gRPC сервер запущен на :50051")
grpcServer.Serve(listener)
}
Клиент gRPC:
package main
import (
"context"
"fmt"
"time"
pb "example/proto"
"google.golang.org/grpc"
)
func main() {
conn, _ := grpc.Dial("localhost:50051", grpc.WithInsecure())
defer conn.Close()
client := pb.NewGreeterClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
res, _ := client.SayHello(ctx, &pb.HelloRequest{Name: "Мир"})
fmt.Println(res.Message)
}
8.4 Вебсокеты #
Для работы с WebSocket используется сторонний пакет, например, github.com/gorilla/websocket
.
Сервер WebSocket:
package main
import (
"fmt"
"net/http"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{}
func wsHandler(w http.ResponseWriter, r *http.Request) {
conn, _ := upgrader.Upgrade(w, r, nil)
defer conn.Close()
for {
_, message, err := conn.ReadMessage()
if err != nil {
break
}
fmt.Println("Получено:", string(message))
conn.WriteMessage(websocket.TextMessage, []byte("Ответ: "+string(message)))
}
}
func main() {
http.HandleFunc("/ws", wsHandler)
fmt.Println("WebSocket сервер запущен на :8080/ws")
http.ListenAndServe(":8080", nil)
}
Клиент WebSocket:
package main
import (
"fmt"
"github.com/gorilla/websocket"
)
func main() {
conn, _, _ := websocket.DefaultDialer.Dial("ws://localhost:8080/ws", nil)
defer conn.Close()
conn.WriteMessage(websocket.TextMessage, []byte("Привет, WebSocket!"))
_, message, _ := conn.ReadMessage()
fmt.Println("Ответ:", string(message))
}
8.5 Работа с REST API #
Отправка GET-запроса:
package main
import (
"encoding/json"
"fmt"
"net/http"
)
type Post struct {
UserID int `json:"userId"`
ID int `json:"id"`
Title string `json:"title"`
Body string `json:"body"`
}
func main() {
resp, _ := http.Get("https://jsonplaceholder.typicode.com/posts/1")
defer resp.Body.Close()
var post Post
json.NewDecoder(resp.Body).Decode(&post)
fmt.Println(post)
}
Отправка POST-запроса:
package main
import (
"bytes"
"fmt"
"net/http"
)
func main() {
jsonData := []byte(`{"title": "foo", "body": "bar", "userId": 1}`)
resp, _ := http.Post("https://jsonplaceholder.typicode.com/posts", "application/json", bytes.NewBuffer(jsonData))
defer resp.Body.Close()
fmt.Println("Ответ сервера:", resp.Status)
}
Эти примеры покрывают основы сетевого программирования в Go, от низкоуровневого TCP до высокоуровневых HTTP и gRPC.