go tcp 双向通信

文章目录

  • serve
  • client

go中tcp客户端请求读(接收)写(发送)必须在不同的协程进行,否则会死锁
go中tcp客户端请求以写(发送)为主,所以write必须在主协程中进行
不能在死循环中使用go创建协程,否则缓存溢出
go中tcp服务端读(接收)写(发送)需要不同协程处理,否则死锁
go中tcp服务端死循环中,使用Accept(),在运行时只有在新创建tcp握手连接才会循环一次,底层runtime管理实现的

serve

package main

import (
	"bufio"
	"fmt"
	"log"
	"net"
	"os"
	"strings"
)

const (
	LogPath  = "./log.txt"
	Protocol = "tcp"
	Addr     = "127.0.0.1:20000"
)

var (
	clientMap = make(map[string]net.Conn)
)

func read(conn net.Conn) {
	defer (func() {
		if conn != nil {
			defer conn.Close()
		}
	})()
	for {
		if conn == nil {
			return
		}
		var buf [128]byte
		n, err := conn.Read(buf[:])
		if err != nil {
			log.Println(err)
			break
		}
		recvStr := string(buf[:n])
		fmt.Println("客户端发来的:", recvStr)
	}
}

func write(conn net.Conn) {
	defer (func() {
		if conn != nil {
			defer conn.Close()
		}
	})()
	for {
		inputReader := bufio.NewReader(os.Stdin)
		s, _ := inputReader.ReadString('\n')
		t := strings.Trim(s, "\r\n")
		if "Q" == t {
			return
		}
		conn.Write([]byte(t))
	}
}

func main() {
	f, err := os.Open(LogPath)
	if err != nil {
		f, err = os.Create(LogPath)
		if err != nil {
			panic(err)
		}
	}
	log.SetOutput(f)

	listen, err := net.Listen(Protocol, Addr)
	if err != nil {
		log.Println(err)
		return
	}

	for {
		conn, err := listen.Accept()
		if err != nil {
			log.Println(err)
			continue
		}
		key := conn.RemoteAddr().String()
		saveConn := clientMap[key]
		if saveConn == nil {
			fmt.Println("client of:", key)
			clientMap[key] = conn
			go write(conn)
			go read(conn)
		}
	}
}

client

package main

import (
	"bufio"
	"fmt"
	"net"
	"os"
	"strings"
)

const (
	Protocol = "tcp"
	Addr     = "127.0.0.1:20000"
)

var (
	inputReader *bufio.Reader
)

func read(conn net.Conn) {
	buf := [512]byte{}
	n, err := conn.Read(buf[:])
	if err != nil {
		fmt.Println("client read :", err)
		os.Exit(0)
		return
	}
	fmt.Println("服务端发来的: ", string(buf[:n]))
}

func write(conn net.Conn) {
	go read(conn)
	input, _ := inputReader.ReadString('\n')
	inputInfo := strings.Trim(input, "\r\n")
	if strings.ToUpper(inputInfo) == "Q" {
		return
	}
	_, err := conn.Write([]byte(inputInfo))
	if err != nil {
		fmt.Println("client write :", err)
	}
}

func main() {
	conn, err := net.Dial(Protocol, Addr)
	if err != nil {
		fmt.Println("err :", err)
		return
	}
	defer conn.Close()

	inputReader = bufio.NewReader(os.Stdin)
	for {
		write(conn)
	}
}

你可能感兴趣的:(golang,tcp/ip,网络)