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)
}
}