利用Go制作一个基于TCP协议的客户端服务端通信程序|Go主题月

453 阅读3分钟

请看dubug后的代码,那才有注释

需求:

服务端

  • 服务端在本机的8888端口建立TCP监听
  • 为接入的每一个客户端开辟一条独立的协程
  • 循环接收客户端消息,不管客户端说什么,都自动回复“已阅xxx”
  • 如果客户端说的是“bye”,则回复“bye”并断开连接

客户端

  • 拨号连接服务端主机的8888端口,建立连接
  • 循环从标准输入(命令行)读取一行用户输入,向服务端发送
  • 接收并打印服务端信息,如果消息是“bye”,则退出程序

debug前 : server.go 服务端

package TCP通信


import (
	"fmt"
	"net"
	"os"
)

func main() {
	listener, err := net.Listen("tcp", "127.0.0.1:8888")
	ServerHandleError(err,"net.Listen")
	for {
		conn, err := listener.Accept()
		ServerHandleError(err,"listener.Accept")
		go ChatWith(conn)
	}

}

func ChatWith(conn net.Conn) {
	buffer := make([]byte, 1024)
	for {
		n, err := conn.Read(buffer)
		ServerHandleError(err,"conn.Read(buffer)")

		clientMsg := string(buffer[0:n])
		fmt.Printf("收到%v的消息:%s\n",conn.RemoteAddr(),clientMsg)
		if clientMsg!="bye"{
			conn.Write([]byte("已阅:"+clientMsg))
		}else {
			conn.Write([]byte("bye!"))
			break
		}
		conn.Close()
		fmt.Printf("客户端%s已经断开连接",conn.RemoteAddr())

	}

}

func ServerHandleError(err error,when string) {
	if err != nil {
		fmt.Println(err,when)
		os.Exit(1)
	}
}

debug前:client.go 客户端

package TCP通信

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

func main() {
	conn, e:= net.Dial("tcp", "127.0.0.1:8888")
	ClientHandleError(e," net.Dial")

	buffer := make([]byte, 1024)

	reader := bufio.NewReader(os.Stdin)
	for{
		lineBytes, _, _ := reader.ReadLine()
		conn.Write(lineBytes)
		n, e := conn.Read(buffer)
		ClientHandleError(e,"conn.Read(buffer)")
		serverMsg := string(buffer[0:n])
		fmt.Println("服务端:"+serverMsg)
		if serverMsg=="bye!"{
			break
		}
		fmt.Println("Game over!")
	}

}
func ClientHandleError(err error,when string) {
	if err != nil {
		fmt.Println(err,when)
		os.Exit(1)
	}
}

编译运行程序

image.png

我们可以看到,一输入就输出“game over”,然后就断开了。

image.png

image.png

然后开始debug,根据审计代码,我发现输出game over的语句和conn.Close()都放在for循环内了,把这修改后就能成功收发信息了。

debug后 : server.go 服务端

package main
/*
需求:

服务端在本机的8888端口建立TCP监听
为接入的每一个客户端开辟一条独立的协程
循环接收客户端消息,不管客户端说什么,都自动回复“已阅xxx”
如果客户端说的是“bye”,则回复“bye”并断开连接

拨号连接服务端主机的8888端口,建立连接
循环从标准输入(命令行)读取一行用户输入,向服务端发送
接收并打印服务端信息,如果消息是“bye”,则退出程序
*/

import (
	"fmt"
	"net"
	"os"
)

func main() {
	//服务端在本机的8888端口建立TCP监听
	listener, err := net.Listen("tcp", "127.0.0.1:8888")
	ServerHandleError(err,"net.Listen")

	for {
		//循环接入所有客户端,得到专线连接
		conn, e := listener.Accept()
		ServerHandleError(e,"listener.Accept")
		//开辟独立的协程,该客户端聊天
		go ChatWith(conn)
	}

}
//在conn中与客户端对话
func ChatWith(conn net.Conn) {
	//创建一个消息缓冲区
	buffer := make([]byte, 1024)
	for {
		//一个完整的消息回合
		
		//读取客户端发来的消息,存入缓冲区,消息长度为n字节
		n, err := conn.Read(buffer)
		ServerHandleError(err,"conn.Read(buffer)")
		//转换为字符串输出
		clientMsg := string(buffer[0:n])
		fmt.Printf("收到%v的消息:%s\n",conn.RemoteAddr(),clientMsg)
		//回复客户端消息
		if clientMsg!="im off"{
			
			conn.Write([]byte("已阅:"+clientMsg))
		}else {
			conn.Write([]byte("bye!"))
			//跳出会话
			break
		}
	}
	//断开客户端连接
	conn.Close()
	fmt.Printf("客户端%s已经断开连接",conn.RemoteAddr())

}

func ServerHandleError(err error,when string) {
	if err != nil {
		fmt.Println(err,when)
		os.Exit(1)
	}
}


debug后 : client.go 服务端

package main

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

func main() {
	//拨号远程地址,建立TCP连接
	conn, err:= net.Dial("tcp", "127.0.0.1:8888")
	ClientHandleError(err," net.Dial")
	//准备消息缓冲区
	buffer := make([]byte, 1024)
	//准备标准输入读取器
	reader := bufio.NewReader(os.Stdin)

	//源源不断的收发消息
	for{
		//接收命令行输入(一行消息)
		lineBytes, _, _ := reader.ReadLine()
		//向服务端发送
		conn.Write(lineBytes)
		//接收服务端消息,存入缓冲区,长度是n字节
		n, _ := conn.Read(buffef)
		//转化为字符串并打印
		serverMsg := string(buffer[0:n])
		fmt.Println("服务端:",serverMsg)
		//如果服务端说bye就退出循环
		if serverMsg == "bye"{
			break
		}
	}
	fmt.Println("Game over!")


}
func ClientHandleError(err error,when string) {
	if err != nil {
		fmt.Println(err,when)
		os.Exit(1)
	}
}


image.png

image.png