服务端:
服务端程序,在8888端口监听
可以和多个客户端创建链接
链接成功后,客户端发送数据,服务端接收数据并显示在终端上
客户端:
客户端程序,能连接到服务器端的8888端口
客户端可以发送单行数据,然后退出
能通过终端输入数据(输入一行发送一行),并发送给服务器端
//server.go
package main
import (
"fmt"
"net"
)
func process(conn net.Conn) {
defer conn.Close() //关闭链接,不关闭则会导致链接未释放
//循环接收客户端发送数据
for {
buf := make([]byte, 1024) //创建一个新的切片
//如果对方没有read我们则会一直在等
//等待客户端通过conn发送信息
//如果客户端没有write[发送],那么协程就阻塞在这
fmt.Println("等待客户端发送数据")
n, err := conn.Read(buf) //从conn读取这个n非常重要
//它底层每隔一段时间发送一次请求给客户端,判断客户端是否异常退出
fmt.Println("服务器等待客户端发送数据" + conn.RemoteAddr().String())
if err != nil { //判断条件也可以写 err == io.EOF
fmt.Println("服务器的Read出错 err=", err)
return
}
//显示客户端发送的内容到服务器的终端
/*
这里不能够使用Println,因为我们在客户端通过判断\n来结束,如果用println会多一行
这个是把buf字节转为string,这个n非常重要,如果不带n会导致把后面1024个数据全部读到
*/
fmt.Print(string(buf[:n]))
}
}
func main() {
fmt.Println("服务器开始监听")
listen, err := net.Listen("tcp", "localhost:8888")
defer listen.Close()
if err != nil {
fmt.Println("listen err=", err)
return
}
//循环等待客户端链接
for {
//等待客户端链接
fmt.Println("等待客户端链接...")
conn, err := listen.Accept()
if err != nil {
fmt.Println("accept err=", err)
} else {
fmt.Printf("accept, con=%v 客户端ip=%v\n", conn, conn.RemoteAddr().String())
}
//这里起一个协程,服务客户端
go process(conn)
}
}
//client.go
package main
import (
"bufio"
"fmt"
"net"
"os"
)
func main() {
conn, err := net.Dial("tcp", "127.0.0.1:8888")
if err != nil {
fmt.Println("客户端失败 err=", err)
return
}
//功能一,客户端发送单行数据,然后输出
reader := bufio.NewReader(os.Stdin)
//从终端读取一行用户输入并准备发送给服务器
line, err := reader.ReadString('\n') //返回一个字符串
if err != nil {
fmt.Println("radString err=", err)
}
//再将line 发送给服务器
n, err := conn.Write([]byte(line)) //可能存在丢包和网络阻塞
if err != nil {
fmt.Println("conn.Write err=", err)
}
fmt.Printf("客户端发送了 %d 的数据,退出", n)
}
程序拓展,让客户端能多次输入数据(输入一行发送一行),并发送给服务端
在终端输入exit表示退出程序
修改后的代码
//client.go
package main
import (
"bufio"
"fmt"
"net"
"os"
"strings"
)
func main() {
conn, err := net.Dial("tcp", "127.0.0.1:8888")
if err != nil {
fmt.Println("客户端失败 err=", err)
return
}
//功能一,客户端发送单行数据,然后输出
reader := bufio.NewReader(os.Stdin)
for {
//从终端读取一行用户输入并准备发送给服务器
line, err := reader.ReadString('\n') //返回一个字符串
if err != nil {
fmt.Println("radString err=", err)
}
line = strings.Trim(line, " \r\n") //去掉换行符
//如果输入exit则退出
if line == "exit" {
fmt.Println("客户端退出")
break
}
//再将line 发送给服务器
_, err = conn.Write([]byte(line + "\n")) //在上面去掉了换行,在下面补回来 可能存在丢包和网络阻塞
if err != nil {
fmt.Println("conn.Write err=", err)
}
}
}
Q.E.D.