用户通讯系统的简单CS结构

295_尚硅谷_TCP编程快速入门案例分析_哔哩哔哩_bilibili

1.基础客户端处理流程

1)监听端8888
2)接收客户端的tcp链接,建立客户端和服务器端的链接.
3)创建goroutine,处理该链接的请求(通常客户端会通过链接发送请求包)

组件:监听器

 代码

package main

import (
	"fmt"
	"net"
)

func main() {
	fmt.Println("服务器开始监听")
	//参数 tcp协议, 监听本地8888接口
	listen, err := net.Listen("tcp", "0.0.0.0:8888")
	/*
		type Listener interface {
			//Addr返回该接口的网络地址
			Addr ( ) Addr
			// Aecept等待并返回下一个连接到该接口的连接
			Accept()) (c Conn,err error)
			//Close关闭该接口,并使任何阳塞的Accept操作都会不再阻塞并返回错误。
			Close() error
		)
	*/
	if nil != err {
		fmt.Println("监听出错err = ", err)
	}
	defer listen.Close() //延时关闭监听接口
	//循环等待客户端连接
	for {
		fmt.Println("等待客户端连接 ")
		conn, err := listen.Accept() //阻塞等待客户端连接
		if nil != err {
			fmt.Println("Accept err = ", err)
		} else {
			fmt.Println("Accept suc,conn = ", conn)
		}
		
	}

	//fmt.Printf("listen suc=%v", listen)

}

2.基础服务端处理流程

1)建立与服务端的链接
2)发送请求数据[终端],接收服务器端返回的结果数据

3)关闭链接

3.发送数据之后的客户端和服务端

目录结构:

1)客户端

1.首先拨号和服务端建立连接

2.建立一个循环发送信息,每次用Reader从终端接收用户的输入

3.把接收的内容分成byte切片conn.Write()发送给服务端,进入下一次循环

4.输入exit表示退出

package main

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

func main() {
	conn, err := net.Dial("tcp", "127.0.0.1:8888")
	if nil != err {
		fmt.Println("Dial err = ", err)
	}
	fmt.Println("conn成功 ", conn)
	fmt.Println("开始聊天吧!")
	for {
		//功能1:客户端发送单行数据
		reader := bufio.NewReader(os.Stdin) //os.Stdin代表终端标准输入
		//1.从终端读取用户输入
		line, err := reader.ReadString('\n')
		if nil != err {
			fmt.Println("ReadString err = ", err)
		}
		//如果输入exit代表退出
		line = strings.Trim(line, " \r\n") //去掉string里的换行和空格
		if "exit" == line {
			fmt.Println("客户端退出")
			return
		}

		//2.然后发送line给服务器(要求参数是byte切片,所以转换一下)
		n, err := conn.Write([]byte(line + "\n"))
		if nil != err {
			fmt.Println("conn.Write err = ", err)
		}
		fmt.Printf("客户端发送了%d字节的数据,并退出\n", n)
	}

}

2)服务端

1.建立服务端端口监听器,接收的信息会从这个端口来

2.循环等待客户端连接通过端口发送消息,没有接收到消息那么监听器就阻塞

3.监听器收到消息就会返回一个和客户端的连接

4.建立一个协程专门处理这个客户端的事务

5.协程用一个循环大容量byte切片接收连接传过来的值,conn.Read(buf),

6.如果接收到内容就在服务端输出

7.如果接收或者连接出问题就退出协程

package main

import (
	"fmt"
	"net"
)

// 协程,处理客户端消息
func process(conn net.Conn) {
	//这里我们循环的接收客户端发送的数据
	defer conn.Close() //关闭conn

	for {
		//创建一个新的切片
		buf := make([]byte, 1024)
		//conn. Read(buf)
		//1.等待客户端通过conn发送信息
		//2.如果客户端没有wrtie[发送],那么协程就阻塞在这里
		fmt.Printf("服务器在等待客户端%s发送信息\n", conn.RemoteAddr().String())
		n, err := conn.Read(buf) //从conn读取,等待write操作。n代表从连接里读到内容的长度
		if err != nil {
			fmt.Println("服务器的Read err=", err)
			return //连接有问题就关闭这个处理协程·
		}
		//3.显示客户端发送的内容到服务器的终端
		/*
			tips:1.读取的时候已经有换行了,不要Println。
				2.需要从byte切片转成string输出,否则是一串数字码
				3.注意接收值只到第n个之前,因为我们定义的buf默认是长度1024
		*/
		fmt.Print(string(buf[:n]))

	}

}

func main() {
	fmt.Println("服务器开始监听")
	//参数 tcp协议, 监听本地8888接口
	listen, err := net.Listen("tcp", "0.0.0.0:8888")
	/*
		type Listener interface {
			//Addr返回该接口的网络地址
			Addr ( ) Addr
			// Aecept等待并返回下一个连接到该接口的连接
			Accept()) (c Conn,err error)
			//Close关闭该接口,并使任何阳塞的Accept操作都会不再阻塞并返回错误。
			Close() error
		)
	*/
	if nil != err {
		fmt.Println("监听出错err = ", err)
	}
	defer listen.Close() //延时关闭监听接口
	//循环等待客户端连接
	for {
		fmt.Println("等待客户端连接 ")
		conn, err := listen.Accept() //阻塞等待客户端连接
		if nil != err {
			fmt.Println("Accept err = ", err)

		} else {
			fmt.Println("Accept suc,conn = ", conn, "客户端IP", conn.RemoteAddr().String())
		}
		//准备一个协程,接收客户端消息
		go process(conn)
	}

	//fmt.Printf("listen suc=%v", listen)
}

此时就已经实现了多个客户端向服务器发送消息,接下来就要实现服务器处理消息并发送给对应客户端。

猜你喜欢

转载自blog.csdn.net/m0_50973548/article/details/132571794