先来看下面这张图!
这个图清晰的展示了tcp协议下的C/S模型运行机制,首先我们先来执行图片右边的TCP服务器。由于go语言天生支持并发,我们就直接展示并发的服务器模型。
//这是一个用来处理连接进来的用户的函数
func handleconn(conn net.Conn) {
defer conn.Close()
buf:=make([]byte,1024)
//给客户端发送连接成功的信号
conn.Write([]byte("welcome to my server\n"))
for {
//持续读取客户端数据,保存在buf缓冲区中,并处理
n,err:=conn.Read(buf)
if n==0 {
fmt.Println("outtoleave",conn.RemoteAddr().String())
break
}
if err!=nil&&err!=io.EOF {
fmt.Println("read err",err)
return
}
//这里是处理数据的一个示范,把客户端发来的数据全部转化为大写
conn.Write([]byte(strings.ToUpper(string(buf[:n]))))
}
}
func main() {
//图片的第一步,net.listen开启监听,获得listener套接字
listener,err:=net.Listen("tcp","127.0.0.1:6666")
if err!=nil {
fmt.Println("listen err",err)
return
}
defer listener.Close()
for {
//开启图片中的第二步,阻塞等待用户连接
conn,err:=listener.Accept()
if err!=nil {
fmt.Println("accept err",err)
return
}
//每一个连接进来的用户都为其分配一个专属的go进程
go handleconn(conn)
}
}
下面再来实现图片左边的TCP客户端模型,由图可知,相较于服务器模型,客户端模型还要少一步。下面不多比比,直接进代码分析:
package main
import (
"net"
"fmt"
"os"
)
func main() {
//主动发起连接请求
conn,err:=net.Dial("tcp","127.0.0.1:8000")
if err!=nil {
fmt.Println("dial err",err)
return
}
defer conn.Close()
//启动go进程,持续接收用户键盘输入
go func() {
//创建缓冲区
buf:=make([]byte,1024)
for {
//持续接收放进缓冲区buf中
n,err:=os.Stdin.Read(buf)
//错误处理
if err!=nil {
fmt.Println("stdin err",err)
return
}
//接收多少,写多少给服务器
_,err=conn.Write(buf[:n])
if err!=nil {
fmt.Println("write err",err)
return
}
}
}()
//主进程接收服务器信息
buf:=make([]byte,4096)
for {
n,err:=conn.Read(buf)
//没有信息时,说明断开了连接,则主动结束进程
if n==0 {
fmt.Println("与服务器连接断开")
break
}
if err!=nil {
fmt.Println("read err",err)
return
}
//打印接收到的信息
fmt.Println(string(buf[:n]))
}
}
以上两段代码就实现了简单的并发C/S模型,有问题的小伙伴可以在下面给我留言哦!