go网络编程

go网络编程

1. tcp

package netMode

import (
	"fmt"
	"net"
)

var (
	protocol = "tcp"
	addr     = "localhost:9999"
)

func TcpServer() {
	/**
	tcp-server
	1. 监听端口
	2. 创建客户端链接
	3. 接收和发送信息
	4. 关闭链接
	*/

	listener, err := net.Listen(protocol, addr) // 监听端口
	defer listener.Close()
	if err != nil {
		fmt.Println("listen error:", err)
		return
	}

	for {
		con, err := listener.Accept() // 建立客户端链接
		if err != nil {
			fmt.Println("accept error:", err)
			continue
		}

		go func(con net.Conn) {
			defer con.Close() // 关闭链接
			data := make([]byte, 1024)
			n, err := con.Read(data) // 接收数据
			if err != nil {
				fmt.Println("server-read error:", err)
				return
			}
			recvData := string(data[:n])
			fmt.Println("server-read data:", recvData)
			n, err = con.Write([]byte(recvData)) // 发送数据
			if err != nil {
				fmt.Println("server-write error:", err)
				return
			}
			fmt.Println("server-write data:", string(data[:n]))

		}(con)
	}
}

func TcpClient() {
	/**
	tcp-client
	1. 建立链接
	2. 发送和接收数据
	3. 关闭链接
	*/
	dial, err := net.Dial(protocol, addr) // 建立链接
    //dial, err := net.DialTimeout(protocol, addr, time.Second*10)  // 10s超时
	if err != nil {
		fmt.Println("dail error:", err)
		return
	}
	defer dial.Close() // 关闭链接

	buf := make([]byte, 1024)
	sendData := []byte("hello tcp")
	n, err := dial.Write(sendData) // 发送数据
	if err != nil {
		fmt.Println("client-write error:", err)
		return
	}
	fmt.Println("client-write data:", string(sendData))
	n, err = dial.Read(buf) // 接收数据
	if err != nil {
		fmt.Println("client-read error:", err)
		return
	}
	fmt.Println("client-read data:", string(buf[:n]))
}
serverOut:
    server-read data: hello tcp
    server-write data: hello tcp
clientOut:
	client-write data: hello tcp
	client-read data: hello tcp

2. udp

package netMode

import (
	"fmt"
	"net"
)

func UdpServer() {
	/**
	udp-server:
	1. 监听端口
	2. 接收和发送信息
	3. 关闭链接
	*/
	listener, err := net.ListenUDP("udp", &net.UDPAddr{
		net.IPv4(0, 0, 0, 0),
		9999,
		"",
	})
	defer listener.Close()
	if err != nil {
		fmt.Println("listen error:", err)
		return
	}

	for {
		buf := make([]byte, 1024)
		n, udpAddr, err := listener.ReadFromUDP(buf) // 接收消息
		if err != nil {
			fmt.Println("server-read error:", err)
			continue
		}
		fmt.Printf("server-read(client:%s)  data:%s\n", udpAddr, string(buf[:n]))

		sendData := []byte(udpAddr.String())
		n, err = listener.WriteToUDP(sendData, udpAddr) // 发送消息
		if err != nil {
			fmt.Println("server-write error:", err)
			continue
		}
		fmt.Println("server-write data:", string(sendData))
	}
}

func UdpClient() {
	/**
	udp-client:
	1. 建立链接
	2. 发送和接收数据
	3. 关闭链接
	*/
	udpAddr, err := net.ResolveUDPAddr("", ":9999") // network默认为udp
	if err != nil {
		fmt.Println("client-resolve error:", err)
		return
	}

	con, err := net.DialUDP("udp", nil, udpAddr) // 建立链接
	if err != nil {
		fmt.Println("client-dial error:", err)
		return
	}
	defer con.Close()
	sendData := []byte("hello udp")
	_, err = con.Write(sendData) // 发送消息
	if err != nil {
		fmt.Println("client-write error:", err)
		return
	}
	fmt.Println("client-write:", string(sendData))

	buf := make([]byte, 1024)
	n, addr, err := con.ReadFromUDP(buf) // 接收消息
	if err != nil {
		fmt.Printf("clien-read(server:%s) error: %s\n", addr, err.Error())
		return
	}
	fmt.Printf("client-read(server:%s) data:%s\n", addr, string(buf[:n]))

}

func UdpBroadCastServer() {
	serverAddr, err := net.ResolveUDPAddr("udp4", ":9999")
	if err != nil {
		fmt.Println("server-resolve error:", err)
		return
	}

	udp, err := net.ListenUDP("udp4", serverAddr)
	if err != nil {
		fmt.Println("server-listen error:", err)
		return
	}

	broadCastAddr, err := net.ResolveUDPAddr("udp4", "255.255.255.255:9999") // 广播地址
	if err != nil {
		fmt.Println("server-resolve-broadCast error:", err)
		return
	}

	for {
		send := []byte("hello broadcast")
		_, err := udp.WriteToUDP(send, broadCastAddr) // 广播形式发送数据
		if err != nil {
			fmt.Println("server-write error:", err)
			return
		}
		fmt.Println("server-broadcast data:", string(send))
	}
}

func UdpBroadCastClient(serverAddr *net.UDPAddr) {
	udpAddr, err := net.ResolveUDPAddr("udp4", ":9999")
	if err != nil {
		fmt.Println("client-resolve error:", err)
		return
	}
	udp, err := net.DialUDP("udp4", udpAddr, serverAddr)
	if err != nil {
		fmt.Println("client-dial error:", err)
		return
	}

	buf := make([]byte, 1024)
	n, addr, err := udp.ReadFromUDP(buf)
	if err != nil {
		fmt.Println("client-read error:", err)
		return
	}
	fmt.Printf("client-read(server:%s) data:%s\n", addr, string(buf[:n]))
}

serverOut:
    server-read(client:127.0.0.1:63379)  data:hello udp
    server-write-broadcast data: 127.0.0.1:63379

clientOut:
	client-write: hello udp
	client-read(server:127.0.0.1:9999) data:127.0.0.1:63379

3. http

package netMode

import (
	"fmt"
	"io"
	"net/http"
)

func HttpServer() {
	/**
	http-server
	1. 定义handler(路由函数)
	2. 创建http服务端并监听特定端口
	*/
	http.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
		fmt.Println("请求信息====>")
		fmt.Println("addr:", r.RemoteAddr)
		fmt.Println("method:", r.Method)
		fmt.Println("url:", r.URL.Path)
		fmt.Println("header:", r.Header)
		fmt.Println("body:", r.Body)
		fmt.Println("响应====>")
		w.Write([]byte("ok"))
	})

	http.ListenAndServe(":9999", nil)
}

func HttpClient() {
	/**
	http-client
	1. 确认请求地址
	2. 构建参数发起请求
	3. 获取结果
	*/
	resp, err := http.Get("http://localhost:9999/test")
	if err != nil {
		fmt.Println("error:", err)
	}
	defer resp.Body.Close()
	buffer := make([]byte, 1024)
	for {
		n, err := resp.Body.Read(buffer)
		if err != nil && err != io.EOF {
			fmt.Println("error:", err)
			break
		} else {
			fmt.Println("data:", string(buffer[:n]))
			break
		}
	}

}
serverOut:
    请求信息====>
    addr: 127.0.0.1:52995
    method: GET
    url: /test
    header: map[Accept-Encoding:[gzip] User-Agent:[Go-http-client/1.1]]
    body: {}
    响应====>
clientOut:
	data: ok

4. websocket

go get -u github.com/gorilla/websocket
package netMode

import (
	"fmt"
	"github.com/gorilla/websocket"
	"net/http"
)

func WebSocketServer() {
	// websocket配置
	upgrader := websocket.Upgrader{
		HandshakeTimeout: 0,    // 升级websocket握手完成的超时时间
		ReadBufferSize:   1024, // io操作读缓冲区大小
		WriteBufferSize:  1024, // // io操作写缓冲区大小
		WriteBufferPool:  nil,  // io操作写缓存池大小
		Subprotocols:     nil,  // 服务支持的协议 []string
		Error:            nil,  // 异常响应处理函数 func(w http.ResponseWriter, r *http.Request, status int, reason error)
		CheckOrigin: func(r *http.Request) bool {
			return true
		},                        // origin头信息检测
		EnableCompression: false, // 是否数据压缩
	}
	// 创建http服务器
	http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
		// 升级http协议为websocket
		con, err := upgrader.Upgrade(w, r, nil)
		if err != nil {
			fmt.Println("websocket-upgrade-error:", err)
			return
		}
		defer con.Close()
		// 发送消息
		sendData := []byte("server-websocket")
		err = con.WriteMessage(websocket.TextMessage, sendData)
		if err != nil {
			fmt.Println("server-write-error:", err)
			return
		}
		fmt.Println("server-write-data:", string(sendData))

		// 接收消息
		messageType, p, err := con.ReadMessage()
		if err != nil {
			fmt.Println("server-read-error:", err)
			return
		}
		fmt.Println("server-read-data:", string(p), messageType)

	})

	// 端口监听
	http.ListenAndServe(":9999", nil)
}

func WebSocketClient() {
	// 链接websocket服务端(一次握手)
	dial, _, err := websocket.DefaultDialer.Dial("ws://localhost:9999/ws", nil)
	if err != nil {
		fmt.Println("client-connect-error:", err)
		return
	}
	defer dial.Close()
	// 发送消息
	sendData := []byte("client-websocket")
	err = dial.WriteMessage(1, sendData)
	if err != nil {
		fmt.Println("client-write-error:", err)
		return
	}
	fmt.Println("client-write-data:", string(sendData))

	// 接收消息
	messageType, p, err := dial.ReadMessage()
	if err != nil {
		fmt.Println("client-read-error:", err)
		return
	}
	fmt.Println("client-read-data:", string(p), messageType)

}
serverOut:
    server-write-data: server-websocket
    server-read-data: client-websocket 1
clientOut:
	client-write-data: client-websocket 
	client-read-data: server-websocket 1

5. rpc

https://books.studygolang.com/go-rpc-programming-guide/part1/gorpc.html
package netMode

import (
	"fmt"
	"net"
	"net/http"
	"net/rpc"
)

type Args struct {
	A, B int
}

type Quotient struct {
	Quo, Rem int
}

type Arith int

func (t *Arith) Multiply(args *Args, reply *int) error {
	*reply = args.A * args.B
	return nil
}

func (t *Arith) Divide(args *Args, quo *Quotient) error {
	quo.Quo = args.A + args.B
	quo.Rem = args.A - args.B
	return nil
}

func RpcServer() {
	/**
	官方例子
	1. 定义输入和输出参数的数据结构
	2. 定义服务对象 Arith 可以是基本类型、也可以是interface{}
	3. 定义2个服务方法 Multiply|Divide
	4. 实现rpc服务器
	*/
	// 生成服务对象
	arith := new(Arith)
	// 注册服务
	rpc.Register(arith)
	// 服务业务处理绑定
	rpc.HandleHTTP()
    // tcp监听
	listen, err := net.Listen("tcp", ":9999")
	if err != nil {
		fmt.Println("listen error:", err)
		return
	}
	// 与http客户端连接 并新建一个新的协程处理
	go http.Serve(listen, nil)
	select {}

}

func RpcClient() {
	// 连接服务端
	dial, err := rpc.DialHTTP("tcp", ":9999")
	if err != nil {
		fmt.Println("client-connect-error:", err)
		return
	}
	defer dial.Close()
	args := Args{10, 11}
	var reply int
	// 同步远程调用
	err = dial.Call("Arith.Multiply", args, &reply)
	if err != nil {
		fmt.Println("client-sync-call-error:", err)
		return
	}
	fmt.Printf("client-sync-call-data(%d*%d):%d\n", args.A, args.B, reply)
	// 异步远程调用
	quotient := new(Quotient)
	call := dial.Go("Arith.Divide", args, quotient, nil)
	fmt.Println("client-async-call-method:", call.ServiceMethod)
	fmt.Println("client-async-call-args:", call.Args)
	fmt.Println("client-async-call-done:", <-call.Done)
	fmt.Println("client-async-call-reply:", call.Reply)
}
clientOut:
	client-call-data(10*11):110
    call-method: Arith.Divide
    call-args: {10 11}
    call-done: &{Arith.Divide {10 11} 0xc0001a2b80 <nil> 0xc000056540}
    call-reply: &{21 -1}


6. grpc

1. grpc参考文档
https://www.topgoer.cn/docs/grpc/grpc-1d2ud3fh1d74h

2. 前置要求
2.1 go环境已添加到环境变量
2.2 protoc编译器下载
	windows下载protoc-27.2-win64.zip、linux选择版本下载
	https://github.com/protocolbuffers/protobuf/releases
2.3 protobuf文件所需exe应用和grpc服务所需依赖
	go get -u google.golang.org/grpc
    go install google.golang.org/protobuf/cmd/protoc-gen-go
    go install google.golang.org/grpc/cmd/protoc-gen-go-grpc
    
2.4 将下载的exe迁移到go环境/bin目录下
	|----bin
	|----bin/go.exe
	|----bin/protoc.exe
	|----bin/protc-gen-go.exe
	|----bin/protoc-gen-go-grpc.exe
		
2.5 编写proto文件

2.6 命令生成当前开发语言适配的源码
protoc --go_out=. --go-grpc_out=. proto/test.proto

2.7 实例
|----netMode
|----netMode/grpcDemo.go
|----netMode/proto/test.proto
|----netMode/proto/test.pb.go
|----netMode/proto/test_grpc.pb.go
// proto文件写法
// 1.syntax: 指定协议版本
syntax="proto3";

// 2.package:指定包名
package <包名>;
// 2.1 go语言包含该选项
option go_package="包名";

// 3.message:指定输入输出信息;驼峰命名message;
message TestReq {
	// 内部字段名规范
	// 格式: 修饰符 数据类型 字段名 = 序号值  [default=默认值]
	// 修饰符: required(必选字段 不传使用类型默认值)|optional(可选-默认)|repeated(多个)
	// 数据类型: bool|double|float|int32|uint32|int64|uint64|sint32|sint64|fixed32|fixed64|sfixed32|sfixed64|string|bytes|enum|message
	// 字段名: 下划线驼峰 eg: a_b
	// 序号值: 范围(1~2^32); 1~15效率最高; 1900~2000不建议使用 protobuf内部使用;
	string per_name = 1;
	int32 per_age = 2;
	Status status = 3;
	map<string,string> info = 4;
}

message TestRes {
	string msg = 1;
	string code = 2;
}

// 3.1数据类型enum介绍;驼峰命名;字段名用大写字母加下划线;字段值必须有个为0;
enum Status {
	IS_OK = 0;
	IS_FAIL = 1;
}

// 4.service: 指定rpc服务接口;驼峰式命名service
service MyService {
	rpc Query (TestReq) returns (TestRes){}
}

// ps: protoc 编译器生成*.proto
protoc --go_out=. --go-grpc_out=. proto/test.proto
syntax="proto3";

option go_package = "/proto";

service TestService {
  rpc Query (TestReq) returns (TestRes){}
}

message TestReq {
  string name = 1;
  int32 age = 2;
  enum Sex {
    male = 0;
    female = 1;
  }
  Sex sex = 3;
  repeated string score = 4;
}

message TestRes {
  map<string, string> info = 1;
}
package netMode

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"net"
	"strings"
	pb "workProject/src/apps/netMode/proto"
)

/**
windows下载protoc-27.2-win64.zip
https://github.com/protocolbuffers/protobuf/releases

go get -u google.golang.org/grpc
go install google.golang.org/protobuf/cmd/protoc-gen-go
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc

protoc --go_out=. --go-grpc_out=. po/test.po
*/

type GrpcServer_ struct {
	*pb.UnimplementedTestServiceServer
}

func (server *GrpcServer_) Query(ctx context.Context, req *pb.TestReq) (res *pb.TestRes, err error) {
	fmt.Println("server-get-req:", req)
	resMap := map[string]string{
		"name":  req.GetName(),
		"age":   string(req.GetAge()),
		"sex":   req.GetSex().String(),
		"score": fmt.Sprintf(strings.Join(req.GetScore(), ",")),
	}
	res = &pb.TestRes{
		Info: resMap,
	}
	return res, nil
}

func GrpcServer() {
	// 创建tcp连接
	listen, err := net.Listen("tcp", ":9999")
	if err != nil {
		fmt.Println("server-listen-error:", err)
		return
	}
	// 实例grpc服务端
	server := grpc.NewServer()
	// 服务注册
	pb.RegisterTestServiceServer(server, &GrpcServer_{})

	defer func() {
		server.Stop()
		listen.Close()
	}()

	fmt.Println("server-listen:9999")
	// 服务启动
	err = server.Serve(listen)
	if err != nil {
		fmt.Println("server-run-error:", err)
		return
	}

}

func GrpcClient() {
	// 新建连接
	conn, err := grpc.NewClient(":9999", grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		fmt.Println("client-connect-error:", err)
		return
	}
	defer conn.Close()
	// 新建客户端
	client := pb.NewTestServiceClient(conn)
	// 新建请求参数
	req := pb.TestReq{
		Name:  "张三",
		Age:   18,
		Sex:   0,
		Score: []string{"10", "20", "30"},
	}
	// 调用接口服务
	query, err := client.Query(context.TODO(), &req)
	if err != nil {
		fmt.Println("client-req-error:", err)
		return
	}
	fmt.Println("client-req-data:", query.GetInfo())
}
serverOut:
	server-listen:9999
	server-get-req: name:"张三"  age:18  score:"10"  score:"20"  score:"30"
clientOut:
	client-req-data: map[age: name:张三 score:10,20,30 sex:male]

posted @   爱编程_喵  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
jQuery火箭图标返回顶部代码

jQuery火箭图标返回顶部代码

滚动滑动条后,查看右下角查看效果。很炫哦!!

适用浏览器:IE8、360、FireFox、Chrome、Safari、Opera、傲游、搜狗、世界之窗.

点击右上角即可分享
微信分享提示