|
|
package netProgram
|
|
|
|
|
|
import (
|
|
|
"bytes"
|
|
|
"context"
|
|
|
"encoding/gob"
|
|
|
"encoding/json"
|
|
|
"errors"
|
|
|
"io"
|
|
|
"log"
|
|
|
"math/rand"
|
|
|
"net"
|
|
|
"sync"
|
|
|
"time"
|
|
|
)
|
|
|
|
|
|
const tcp = "tcp"
|
|
|
|
|
|
// 服务端
|
|
|
func TcpServer() {
|
|
|
// A. 基于某个地址建立监听
|
|
|
// 服务端地址
|
|
|
//address := "127.0.0.1:5678"
|
|
|
// 端口省略,会使用随机端口
|
|
|
//address := "127.0.0.1:"
|
|
|
// IP省略,使用服务器全部的可用IP
|
|
|
|
|
|
// tcp协议类型
|
|
|
//address := "127.0.0.1:5678" // IPv4
|
|
|
//address := "[::1]:5678" // IPv6
|
|
|
address := ":5678" // Any IP or version
|
|
|
listener, err := net.Listen(tcp, address)
|
|
|
if err != nil {
|
|
|
log.Fatalln(err)
|
|
|
}
|
|
|
// 关闭监听
|
|
|
defer listener.Close()
|
|
|
log.Printf("%s server is listening on %s\n", tcp, listener.Addr())
|
|
|
|
|
|
// B. 接受连接请求
|
|
|
// 循环接受
|
|
|
for {
|
|
|
// 阻塞接受
|
|
|
conn, err := listener.Accept()
|
|
|
if err != nil {
|
|
|
log.Println(err)
|
|
|
}
|
|
|
|
|
|
// 处理连接,读写
|
|
|
// 日志连接的远程地址(client addr)
|
|
|
log.Printf("accept from %s\n", conn.RemoteAddr())
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 基本读写操作
|
|
|
func TcpServerRW() {
|
|
|
// A. 基于某个地址建立监听
|
|
|
// 服务端地址
|
|
|
address := ":5678" // Any IP or version
|
|
|
listener, err := net.Listen(tcp, address)
|
|
|
if err != nil {
|
|
|
log.Fatalln(err)
|
|
|
}
|
|
|
// 关闭监听
|
|
|
defer listener.Close()
|
|
|
log.Printf("%s server is listening on %s\n", tcp, listener.Addr())
|
|
|
|
|
|
// B. 接受连接请求
|
|
|
// 循环接受
|
|
|
for {
|
|
|
// 阻塞接受
|
|
|
conn, err := listener.Accept()
|
|
|
if err != nil {
|
|
|
log.Println(err)
|
|
|
}
|
|
|
|
|
|
// 处理连接,读写
|
|
|
go HandleConn(conn)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 服务端
|
|
|
func TcpBacklogServer() {
|
|
|
// A. 基于某个地址建立监听
|
|
|
// 服务端地址
|
|
|
address := ":5678" // Any IP or version
|
|
|
listener, err := net.Listen(tcp, address)
|
|
|
if err != nil {
|
|
|
log.Fatalln(err)
|
|
|
}
|
|
|
// 关闭监听
|
|
|
defer listener.Close()
|
|
|
log.Printf("%s server is listening on %s\n", tcp, listener.Addr())
|
|
|
|
|
|
// B. 接受连接请求
|
|
|
// 循环接受
|
|
|
for {
|
|
|
// 阻塞接受
|
|
|
conn, err := listener.Accept()
|
|
|
if err != nil {
|
|
|
log.Println(err)
|
|
|
}
|
|
|
|
|
|
// 处理连接,读写
|
|
|
go func(conn net.Conn) {
|
|
|
// 日志连接的远程地址(client addr)
|
|
|
log.Printf("accept from %s\n", conn.RemoteAddr())
|
|
|
time.Sleep(time.Second)
|
|
|
}(conn)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 处理每个连接
|
|
|
func HandleConn(conn net.Conn) {
|
|
|
// 日志连接的远程地址(client addr)
|
|
|
log.Printf("accept from %s\n", conn.RemoteAddr())
|
|
|
|
|
|
// A.保证连接关闭
|
|
|
defer conn.Close()
|
|
|
|
|
|
// B.向客户端发送数据,SerWrite
|
|
|
wn, err := conn.Write([]byte("send some data from server" + "\n"))
|
|
|
if err != nil {
|
|
|
log.Println(err)
|
|
|
}
|
|
|
log.Printf("server write len is %d\n", wn)
|
|
|
|
|
|
// C.从客户端接收数据,SerRead
|
|
|
buf := make([]byte, 1024)
|
|
|
rn, err := conn.Read(buf)
|
|
|
if err != nil {
|
|
|
log.Println(err)
|
|
|
}
|
|
|
log.Println("received from client data is:", string(buf[:rn]))
|
|
|
}
|
|
|
|
|
|
// 基本读写操作
|
|
|
func TcpW() {
|
|
|
// A. 基于某个地址建立监听
|
|
|
// 服务端地址
|
|
|
address := ":5678" // Any IP or version
|
|
|
listener, err := net.Listen(tcp, address)
|
|
|
if err != nil {
|
|
|
log.Fatalln(err)
|
|
|
}
|
|
|
// 关闭监听
|
|
|
defer listener.Close()
|
|
|
log.Printf("%s server is listening on %s\n", tcp, listener.Addr())
|
|
|
|
|
|
// B. 接受连接请求
|
|
|
// 循环接受
|
|
|
for {
|
|
|
// 阻塞接受
|
|
|
conn, err := listener.Accept()
|
|
|
if err != nil {
|
|
|
log.Println(err)
|
|
|
}
|
|
|
|
|
|
// 处理连接,读写
|
|
|
go HandleConnW(conn)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 处理每个连接
|
|
|
func HandleConnW(conn net.Conn) {
|
|
|
// 日志连接的远程地址(client addr)
|
|
|
log.Printf("accept from %s\n", conn.RemoteAddr())
|
|
|
|
|
|
// A.保证连接关闭
|
|
|
defer conn.Close()
|
|
|
|
|
|
// 1. 严谨的判断是否写入成功
|
|
|
//data := []byte("send some data from server" + "\n")
|
|
|
//wn, err := conn.SerWrite(data)
|
|
|
//if err != nil {
|
|
|
// log.Println(err)
|
|
|
//}
|
|
|
//// 若要严谨的判断是否写入成功,需要:
|
|
|
//if err == nil && wn == len(data) {
|
|
|
// log.Println("write success")
|
|
|
//}
|
|
|
//log.Printf("server write len is %d\n", wn)
|
|
|
|
|
|
// 2. 写操作会被阻塞
|
|
|
//for i := 0; i < 300000; i++ {
|
|
|
// data := []byte("send some data from server" + "\n")
|
|
|
// wn, err := conn.SerWrite(data)
|
|
|
// if err != nil {
|
|
|
// log.Fatalln(err)
|
|
|
// }
|
|
|
// log.Printf("%d, server write len is %d\n", i, wn)
|
|
|
//}
|
|
|
|
|
|
// 不执行任何写操作
|
|
|
//time.Sleep(5 * time.Second)
|
|
|
|
|
|
// 写入一次
|
|
|
data := []byte("send some data from server" + "\n")
|
|
|
wn, err := conn.Write(data)
|
|
|
if err != nil {
|
|
|
log.Println(err)
|
|
|
}
|
|
|
// 若要严谨的判断是否写入成功,需要:
|
|
|
if err == nil && wn == len(data) {
|
|
|
log.Println("write success")
|
|
|
}
|
|
|
log.Printf("server write len is %d\n", wn)
|
|
|
}
|
|
|
|
|
|
// 并发的读和写操作,全双工
|
|
|
func TcpServerRWConcurrency() {
|
|
|
// A. 基于某个地址建立监听
|
|
|
// 服务端地址
|
|
|
address := ":5678" // Any IP or version
|
|
|
listener, err := net.Listen(tcp, address)
|
|
|
if err != nil {
|
|
|
log.Fatalln(err)
|
|
|
}
|
|
|
// 关闭监听
|
|
|
defer listener.Close()
|
|
|
log.Printf("%s server is listening on %s\n", tcp, listener.Addr())
|
|
|
|
|
|
// B. 接受连接请求
|
|
|
// 循环接受
|
|
|
for {
|
|
|
// 阻塞接受
|
|
|
conn, err := listener.Accept()
|
|
|
if err != nil {
|
|
|
log.Println(err)
|
|
|
}
|
|
|
|
|
|
// 处理连接,读写
|
|
|
go HandleConnConcurrency(conn)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 处理每个连接
|
|
|
func HandleConnConcurrency(conn net.Conn) {
|
|
|
// 日志连接的远程地址(client addr)
|
|
|
log.Printf("accept from %s\n", conn.RemoteAddr())
|
|
|
// A.保证连接关闭
|
|
|
defer conn.Close()
|
|
|
|
|
|
wg := sync.WaitGroup{}
|
|
|
// 并发的写
|
|
|
wg.Add(1)
|
|
|
go SerWrite(conn, &wg, "abcd")
|
|
|
wg.Add(1)
|
|
|
go SerWrite(conn, &wg, "efgh")
|
|
|
wg.Add(1)
|
|
|
go SerWrite(conn, &wg, "ijkl")
|
|
|
|
|
|
// 并发的读
|
|
|
wg.Add(1)
|
|
|
go SerRead(conn, &wg)
|
|
|
|
|
|
wg.Wait()
|
|
|
}
|
|
|
|
|
|
func SerWrite(conn net.Conn, wg *sync.WaitGroup, data string) {
|
|
|
defer wg.Done()
|
|
|
// B.向客户端发送数据,SerWrite
|
|
|
for {
|
|
|
wn, err := conn.Write([]byte(data + "\n"))
|
|
|
if err != nil {
|
|
|
log.Println(err)
|
|
|
}
|
|
|
log.Printf("server write len is %d\n", wn)
|
|
|
time.Sleep(1 * time.Second)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func SerRead(conn net.Conn, wg *sync.WaitGroup) {
|
|
|
defer wg.Done()
|
|
|
for {
|
|
|
// C.从客户端接收数据,SerRead
|
|
|
buf := make([]byte, 1024)
|
|
|
rn, err := conn.Read(buf)
|
|
|
if err != nil {
|
|
|
log.Println(err)
|
|
|
}
|
|
|
log.Println("received from client data is:", string(buf[:rn]))
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 格式化传输
|
|
|
func TcpServerFormat() {
|
|
|
// A. 基于某个地址建立监听
|
|
|
// 服务端地址
|
|
|
address := ":5678" // Any IP or version
|
|
|
listener, err := net.Listen(tcp, address)
|
|
|
if err != nil {
|
|
|
log.Fatalln(err)
|
|
|
}
|
|
|
// 关闭监听
|
|
|
defer listener.Close()
|
|
|
log.Printf("%s server is listening on %s\n", tcp, listener.Addr())
|
|
|
|
|
|
// B. 接受连接请求
|
|
|
// 循环接受
|
|
|
for {
|
|
|
// 阻塞接受
|
|
|
conn, err := listener.Accept()
|
|
|
if err != nil {
|
|
|
log.Println(err)
|
|
|
}
|
|
|
|
|
|
// 处理连接,读写
|
|
|
go HandleConnFormat(conn)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func HandleConnFormat(conn net.Conn) {
|
|
|
// 日志连接的远程地址(client addr)
|
|
|
log.Printf("accept from %s\n", conn.RemoteAddr())
|
|
|
// A.保证连接关闭
|
|
|
defer conn.Close()
|
|
|
|
|
|
wg := sync.WaitGroup{}
|
|
|
wg.Add(1)
|
|
|
// 发送端,
|
|
|
go SerWriteFormat(conn, &wg)
|
|
|
wg.Wait()
|
|
|
}
|
|
|
|
|
|
func SerWriteFormat(conn net.Conn, wg *sync.WaitGroup) {
|
|
|
defer wg.Done()
|
|
|
for {
|
|
|
// 向客户端发送数据
|
|
|
// 数据编码后发送
|
|
|
|
|
|
// 创建需要传递的数据
|
|
|
// 自定义的消息结构类型
|
|
|
type Message struct {
|
|
|
ID uint `json:"id,omitempty"`
|
|
|
Code string `json:"code,omitempty"`
|
|
|
Content string `json:"content,omitempty"`
|
|
|
}
|
|
|
message := Message{
|
|
|
ID: uint(rand.Int()),
|
|
|
Code: "SERVER-STANDARD",
|
|
|
Content: "message from server",
|
|
|
}
|
|
|
// 编码后数据的展示
|
|
|
var buf bytes.Buffer
|
|
|
encoderData := json.NewEncoder(&buf)
|
|
|
//encoderData := gob.NewEncoder(&buf)
|
|
|
if err := encoderData.Encode(message); err != nil {
|
|
|
log.Println(err)
|
|
|
continue
|
|
|
}
|
|
|
log.Println(buf.String())
|
|
|
|
|
|
// 1, JSON, 文本编码
|
|
|
//// 创建编码器
|
|
|
//encoder := json.NewEncoder(conn)
|
|
|
//// 利用编码器进行编码
|
|
|
//// encode 成功后,会写入到conn,已经完成了conn.Write()
|
|
|
//if err := encoder.Encode(message); err != nil {
|
|
|
// log.Println(err)
|
|
|
// continue
|
|
|
//}
|
|
|
//log.Println("message was send")
|
|
|
|
|
|
// 2, GOB, 二进制编码
|
|
|
// 创建编码器
|
|
|
encoder := gob.NewEncoder(conn)
|
|
|
// 利用编码器进行编码
|
|
|
// encode 成功后,会写入到conn,已经完成了conn.Write()
|
|
|
if err := encoder.Encode(message); err != nil {
|
|
|
log.Println(err)
|
|
|
continue
|
|
|
}
|
|
|
log.Println("message was send")
|
|
|
|
|
|
time.Sleep(1 * time.Second)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 短连接编程示例
|
|
|
func TcpServerSort() {
|
|
|
// A. 基于某个地址建立监听
|
|
|
// 服务端地址
|
|
|
address := ":5678" // Any IP or version
|
|
|
listener, err := net.Listen(tcp, address)
|
|
|
if err != nil {
|
|
|
log.Fatalln(err)
|
|
|
}
|
|
|
// 关闭监听
|
|
|
defer listener.Close()
|
|
|
log.Printf("%s server is listening on %s\n", tcp, listener.Addr())
|
|
|
|
|
|
// B. 接受连接请求
|
|
|
// 循环接受
|
|
|
for {
|
|
|
// 阻塞接受
|
|
|
conn, err := listener.Accept()
|
|
|
if err != nil {
|
|
|
log.Println(err)
|
|
|
}
|
|
|
|
|
|
// 处理连接,读写
|
|
|
go HandleConnSort(conn)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func HandleConnSort(conn net.Conn) {
|
|
|
// 日志连接的远程地址(client addr)
|
|
|
log.Printf("accept from %s\n", conn.RemoteAddr())
|
|
|
// A.保证连接关闭
|
|
|
defer conn.Close()
|
|
|
|
|
|
wg := sync.WaitGroup{}
|
|
|
wg.Add(1)
|
|
|
// 发送端,
|
|
|
go SerWriteSort(conn, &wg)
|
|
|
wg.Wait()
|
|
|
}
|
|
|
|
|
|
func SerWriteSort(conn net.Conn, wg *sync.WaitGroup) {
|
|
|
defer wg.Done()
|
|
|
|
|
|
// 创建需要传递的数据
|
|
|
// 自定义的消息结构类型
|
|
|
type Message struct {
|
|
|
ID uint `json:"id,omitempty"`
|
|
|
Code string `json:"code,omitempty"`
|
|
|
Content string `json:"content,omitempty"`
|
|
|
}
|
|
|
message := Message{
|
|
|
ID: uint(rand.Int()),
|
|
|
Code: "SERVER-STANDARD",
|
|
|
Content: "message from server",
|
|
|
}
|
|
|
|
|
|
// GOB, 二进制编码
|
|
|
// 创建编码器
|
|
|
encoder := gob.NewEncoder(conn)
|
|
|
// 利用编码器进行编码
|
|
|
// encode 成功后,会写入到conn,已经完成了conn.Write()
|
|
|
if err := encoder.Encode(message); err != nil {
|
|
|
log.Println(err)
|
|
|
return
|
|
|
}
|
|
|
log.Println("message was send")
|
|
|
log.Println("link will be close")
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 心跳检测
|
|
|
func TcpServerHB() {
|
|
|
// A. 基于某个地址建立监听
|
|
|
// 服务端地址
|
|
|
address := ":5678" // Any IP or version
|
|
|
listener, err := net.Listen(tcp, address)
|
|
|
if err != nil {
|
|
|
log.Fatalln(err)
|
|
|
}
|
|
|
// 关闭监听
|
|
|
defer listener.Close()
|
|
|
log.Printf("%s server is listening on %s\n", tcp, listener.Addr())
|
|
|
|
|
|
// B. 接受连接请求
|
|
|
// 循环接受
|
|
|
for {
|
|
|
// 阻塞接受
|
|
|
conn, err := listener.Accept()
|
|
|
if err != nil {
|
|
|
log.Println(err)
|
|
|
}
|
|
|
|
|
|
// 处理连接,读写
|
|
|
go HandleConnHB(conn)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func HandleConnHB(conn net.Conn) {
|
|
|
// 日志连接的远程地址(client addr)
|
|
|
log.Printf("accept from %s\n", conn.RemoteAddr())
|
|
|
// A.保证连接关闭
|
|
|
defer func() {
|
|
|
conn.Close()
|
|
|
log.Println("connection be closed")
|
|
|
}()
|
|
|
|
|
|
wg := sync.WaitGroup{}
|
|
|
|
|
|
// 独立的goroutine,在连接建立后,周期发送ping
|
|
|
wg.Add(1)
|
|
|
// 发送ping
|
|
|
go SerPing(conn, &wg)
|
|
|
wg.Wait()
|
|
|
}
|
|
|
|
|
|
func SerPing(conn net.Conn, wg *sync.WaitGroup) {
|
|
|
defer wg.Done()
|
|
|
|
|
|
// 启动接收pong
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
go SerReadPong(conn, ctx)
|
|
|
|
|
|
// ping失败的次数
|
|
|
const maxPingNum = 3
|
|
|
pingErrCounter := 0
|
|
|
|
|
|
//周期性的发送
|
|
|
//利用 time.Ticker
|
|
|
ticker := time.NewTicker(2 * time.Second)
|
|
|
for t := range ticker.C {
|
|
|
pingMsg := MessageHB{
|
|
|
ID: uint(rand.Int()),
|
|
|
Code: "PING-SERVER",
|
|
|
Time: t,
|
|
|
}
|
|
|
|
|
|
// GOB, 二进制编码
|
|
|
encoder := gob.NewEncoder(conn)
|
|
|
// encode 成功后,会写入到conn,已经完成了conn.Write()
|
|
|
if err := encoder.Encode(pingMsg); err != nil {
|
|
|
log.Println(err)
|
|
|
// 连接有问题的情况
|
|
|
// 累加错误计数器
|
|
|
pingErrCounter++
|
|
|
// 判断是否到达上限
|
|
|
if pingErrCounter == maxPingNum {
|
|
|
// 心跳失败
|
|
|
// 终止pong的处理
|
|
|
cancel()
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
log.Printf("ping send to %s, ping id is %d\n", conn.RemoteAddr(), pingMsg.ID)
|
|
|
}
|
|
|
}
|
|
|
func SerReadPong(conn net.Conn, ctx context.Context) {
|
|
|
|
|
|
for {
|
|
|
// 处理Ping结束
|
|
|
select {
|
|
|
case <-ctx.Done():
|
|
|
return
|
|
|
default:
|
|
|
message := MessageHB{}
|
|
|
// GOB解码
|
|
|
decoder := gob.NewDecoder(conn)
|
|
|
// 解码操作,从conn中读取内容,成功会将解码后的结果,赋值到message变量
|
|
|
err := decoder.Decode(&message)
|
|
|
// 错误 io.EOF 时,表示连接被给关闭
|
|
|
if err != nil && errors.Is(err, io.EOF) {
|
|
|
log.Println(err)
|
|
|
break
|
|
|
}
|
|
|
// 判断是为为 pong 类型消息
|
|
|
if message.Code == "PONG-CLIENT" {
|
|
|
log.Printf("receive pong from %s, %s\n", conn.RemoteAddr(), message.Content)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 测试连接池服务端
|
|
|
func TcpServerPool() {
|
|
|
// A. 基于某个地址建立监听
|
|
|
// 服务端地址
|
|
|
address := ":5678" // Any IP or version
|
|
|
listener, err := net.Listen(tcp, address)
|
|
|
if err != nil {
|
|
|
log.Fatalln(err)
|
|
|
}
|
|
|
// 关闭监听
|
|
|
defer listener.Close()
|
|
|
log.Printf("%s server is listening on %s\n", tcp, listener.Addr())
|
|
|
|
|
|
// B. 接受连接请求
|
|
|
// 循环接受
|
|
|
for {
|
|
|
// 阻塞接受
|
|
|
conn, err := listener.Accept()
|
|
|
if err != nil {
|
|
|
log.Println(err)
|
|
|
}
|
|
|
|
|
|
// 处理连接,读写
|
|
|
go HandleConnPool(conn)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func HandleConnPool(conn net.Conn) {
|
|
|
// 日志连接的远程地址(client addr)
|
|
|
log.Printf("accept from %s\n", conn.RemoteAddr())
|
|
|
// A.保证连接关闭
|
|
|
defer func() {
|
|
|
conn.Close()
|
|
|
log.Println("connection be closed")
|
|
|
}()
|
|
|
|
|
|
select {}
|
|
|
}
|