Go语言如何实现TCP通信详解

2023-01-08 09:51:43
目录
前言TCP连接TCP服务端总结

前言

TCP协议为传输控制协议,TCP协议有以下几个特点:

1.>

2. 每条TCP连接只能有两个端点,每条TCP连接是点到点的通信;

3. TCP提供可靠的交付服务,保证传送的数据无差错,不丢失,不重要且有序;

4. TCP提供全双工通信,允许双方在任何时候都能发送数据,为此TCP连接的两端都设有发送缓存和接收缓存,用来临时存放双向通信的数据;

5. TCP是面向字节流的;

发送缓存用来暂存以下数据:

① 发送应用程序传送给发送方TCP准备发送的数据;

② TCP已发送但尚未收到确认的数据;

接收缓存用来暂存以下数据:

① 按序到达但尚未被接收应用程序读取的数据;

② 不按序到达的数据;

因为是面向连接的协议,数据像水流一样传输,会存在黏包问题。

TCP连接

一个TCP服务端可以同时连接很多个客户端,Go语言可以使用go关键字开启goroutine,每建立一个连接就创建一个goroutine,这样可以并发执行每一个创建的连接,tcp服务端主要的处理流程有:1.>

下面的代码需要先运行服务端的代码,再运行客户端的代码:

TCP服务端

package main
 
import (
	"bufio"
	"fmt"
	"net"
	"os"
	"strings"
)
 
// TCP 服务端
func process(conn net.Conn) {
	// 函数执行完之后关闭连接
	defer conn.Close()
	// 输出主函数传递的conn可以发现属于*TCPConn类型, *TCPConn类型那么就可以调用*TCPConn相关类型的方法, 其中可以调用read()方法读取tcp连接中的数据
	fmt.Printf("服务端: %T\n", conn)
	for {
		var buf [128]byte
		// 将tcp连接读取到的数据读取到byte数组中, 返回读取到的byte的数目
		n, err := conn.Read(buf[:])
		if err != nil {
			// 从客户端读取数据的过程中发生错误
			fmt.Println("read from client failed, err:", err)
			break
		}
		recvStr := string(buf[:n])
		fmt.Println("服务端收到客户端发来的数据:", recvStr)
		// 由于是tcp连接所以双方都可以发送数据, 下面接收服务端发送的数据这样客户端也可以收到对应的数据
		inputReader := bufio.NewReader(os.Stdin)
		s, _ := inputReader.ReadString('\n')
		t := strings.Trim(s, "\r\n")
		// 向当前建立的tcp连接发送数据, 客户端就可以收到服务端发送的数据
		conn.Write([]byte(t))
	}
}
 
func main() {
	// 监听当前的tcp连接
	listen, err := net.Listen("tcp", "127.0.0.1:20000")
	fmt.Printf("服务端: %T=====\n", listen)
	if err != nil {
		fmt.Println("listen failed, err:", err)
		return
	}
	for {
		conn, err := listen.Accept() // 建立连接
		fmt.Println("当前建立了tcp连接")
		if err != nil {
			fmt.Println("accept failed, err:", err)
			continue
		}
		// 对于每一个建立的tcp连接使用go关键字开启一个goroutine处理
		go process(conn) 
	}
}

TCP客户端

package main
 
import (
	"bufio"
	"fmt"
	"net"
	"os"
	"strings"
)
 
func main() {
	// 连接到服务端建立的tcp连接
	conn, err := net.Dial("tcp", "127.0.0.1:20000")
	// 输出当前建Dial函数的返回值类型, 属于*net.TCPConn类型
	fmt.Printf("客户端: %T\n", conn)
	if err != nil {
		// 连接的时候出现错误
		fmt.Println("err :", err)
		return
	}
	// 当函数返回的时候关闭连接
	defer conn.Close() 
	// 获取一个标准输入的*Reader结构体指针类型的变量
	inputReader := bufio.NewReader(os.Stdin)
	for {
		// 调用*Reader结构体指针类型的读取方法
		input, _ := inputReader.ReadString('\n') // 读取用户输入
		// 去除掉\r \n符号
		inputInfo := strings.Trim(input, "\r\n")
		// 判断输入的是否是Q, 如果是Q则退出
		if strings.ToUpper(inputInfo) == "Q" { // 如果输入q就退出
			return
		}
		_, err = conn.Write([]byte(inputInfo)) // 发送数据
		if err != nil {
			return
		}
		buf := [512]byte{}
		// 读取服务端发送的数据
		n, err := conn.Read(buf[:])
		if err != nil {
			fmt.Println("recv failed, err:", err)
			return
		}
		fmt.Println("客户端接收服务端发送的数据: ", string(buf[:n]))
	}
}

总结

到此这篇关于Go语言如何实现TCP通信的文章就介绍到这了,更多相关Go语言TCP通信内容请搜索易采站长站以前的文章或继续浏览下面的相关文章希望大家以后多多支持易采站长站!