golang 实现tcp 服务器(go net包)

go 实现tcp 服务器

TCP基础

传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793 定义。TCP将用户数据打包构成报文段,它发送数据时启动一个定时器,另一端收到数据进行确认,对失序的数据重新排序,丢弃重复的数据。TCP提供一种面向连接的可靠的字节流服务,面向连接意味着两个使用TCP的应用(B/S)在彼此交换数据之前,必须先建立一个TCP连接,类似于打电话过程,先拨号振铃,等待对方说喂,然后应答。在一个TCP连接中,只有两方彼此通信。

GO语言实现

我们将使用 TCP 协议和协程范式编写一个简单的客户端-服务器应用,一个(web)服务器应用需要响应众多客户端的并发请求:**Go 会为每一个客户端产生一个协程用来处理请求。我们需要使用 net 包中网络通信的功能。**它包含了处理 TCP/IP 以及 UDP 协议、域名解析等方法。

golang的net包

golang的net包
参考URL: https://studygolang.com/articles/581

https://golang.org/pkg/net/

import “net”

net包提供了可移植的网络I/O接口,包括TCP/IP、UDP、域名解析和Unix域socket。

虽然本包提供了对网络原语的访问,大部分使用者只需要Dial、Listen和Accept函数提供的基本接口;以及相关的Conn和Listener接口。crypto/tls包提供了相同的接口和类似的Dial和Listen函数。

常用,需掌握!

golang中bufio包

golang中bufio包
参考URL: https://www.imooc.com/article/272890

bufio 包介绍
bufio包实现了有缓冲的I/O。它包装一个io.Reader或io.Writer接口对象,创建另一个也实现了该接口,且同时还提供了缓冲和一些文本I/O的帮助函数的对象。

bufio 是通过缓冲来提高效率

简单的说就是,把文件读取进缓冲(内存)之后再读取的时候就可以避免文件系统的io 从而提高速度。同理,在进行写操作时,先把文件写入缓冲(内存),然后由缓冲写入文件系统。缓冲区的设计是为了存储多次的写入,最后一口气把缓冲区内容写入文件。

常用,需掌握

TCP服务端

go语言中可以每次建立一次链接就创建一个goroutine去处理,使用goroutine实现并发非常方便和高效。

TCP服务端程序的一般处理流程

1.建立并绑定 Socket:首先服务端使用 socket() 函数建立网络套接字,然后使用 bind() 函数为套接字绑定指定的 IP 和端口;

2.监听请求:接下来,服务端使用 listen() 函数监听客户端对绑定 IP 和端口的请求;

3.接收连接:如果有请求过来,并通过三次握手成功建立连接,则使用 accept() 函数接收该链接;

4.创建goroutine去处理链接:服务端通过 read() 函数从上述已建立连接读取客户端发送的请求数据,经过处理后再通过 write() 函数将响应数据发送给客户端

TCP客户端的一般处理流程

1.建立 Socket:客户端同样使用 socket()函数建立网络套接字;

2.建立连接:建立连接:然后调用 connect() 函数传入 IP 和端口号建立与指定服务端网络程序的连接;

3.发送请求与接收响应:连接建立成功后,客户端就可以通过 write() 函数向服务端发送数据,并使用 read() 函数从服务端接收响应。

简单demo示例

server.go

package main

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

func main() {
	fmt.Println("Starting the server ...")
	// 创建 listener
	listener, err := net.Listen("tcp", "127.0.0.1:50000")
	if err != nil {
		fmt.Println("Error listening", err.Error())
		return
	}
	// 监听并接受来自客户端的连接
	for {
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("Error accepting", err.Error())
			return
		}
		// 启动一个goroutine处理连接
		go process(conn)
	}
}

func process(conn net.Conn) {
	// 关闭连接
	defer conn.Close()
	for {
		reader := bufio.NewReader(conn)
		var buf [128]byte
		// 读取数据
		len, err := reader.Read(buf[:])
		if err != nil {
			fmt.Println("read from client failed, err:", err)
			break
		}

		recvStr := string(buf[:len])
		fmt.Println("Received data: ", recvStr)
		// 发送数据
		conn.Write([]byte(recvStr))

	}

}

client.go

package main

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

//tcp client demo
func main() {
	fmt.Println("Starting the client ...")
	//与服务端建立连接
	conn, err := net.Dial("tcp", "127.0.0.1:50000")
	if err != nil {
		fmt.Printf("dial failed, err:%v\n", err)
		return
	}
	//2、利用该连接进行数据的发送和接收
	inputReader := bufio.NewReader(os.Stdin)
	for {
		input, _ := inputReader.ReadString('\n')
		trimmedInput := strings.Trim(input, "\r\n")
		// fmt.Printf("input:--%s--", input)
		// fmt.Printf("trimmedInput:--%s--", trimmedInput)
		if trimmedInput == "Q" {
			return
		}
		//给服务端发消息
		_, err := conn.Write([]byte(trimmedInput))
		if err != nil {
			fmt.Printf("send failed,err:%v\n", err)
			return
		}

		//从服务端接收回复的消息
		var buf [1024]byte
		n, err := conn.Read(buf[:])
		if err != nil {
			fmt.Printf("read failed,err:%v\n", err)
			return
		}
		fmt.Printf("收到服务端回复:%v\n", string(buf[:n]))
	}
}

客户端通过 net.Dial 创建了一个和服务器之间的连接。

它通过无限循环从 os.Stdin 接收来自键盘的输入,直到输入了“Q”。注意裁剪 \r 和 \n 字符(仅 Windows 平台需要)。裁剪后的输入被 connection 的 Write 方法发送到服务器。

参考

[推荐]go语言实现TCP服务端以及客户端、解决TCP黏包问题
参考URL: https://blog.csdn.net/qq_40771567/article/details/108433433
在Go中构建并发TCP服务器样例
参考URL: https://zhuanlan.zhihu.com/p/67570906
go实现tcp 服务器
参考URL: https://www.cnblogs.com/lfri/p/11769254.html
go net包简记
参考URL: https://www.cnblogs.com/-wenli/p/12321196.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西京刀客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值