Go语言学习笔记十一(Telnet回音服务器)

使用Tenlet回音器示例展示TCP服务器的基本结构,回音器服务器代码主要分为四个部分分别是接受连接、会话处理、
Tenlet命令处理和程序入口。
接受连接
回音服务器能同时服务于多个连接,要接受连接就要创建侦听器,侦听器需要一个侦听地址和协议类型。一个服务器可以开启多个侦听器。
telnet服务器处理代码

package main
import(
	"fmt"
	"net"
)
//根据逻辑传入地址和退出通道
func server(address string, exitChan chan int) {
	//根据给定地址进行侦听
	l,err := net.Listen("tcp",address)
	//如果侦听发生错误,打印错误报告并退出
	if err != nil {
		fmt.Println(err.Error())
		exitChan <- 1
		}
	//打印侦听地址,表示侦听成功
	fmt.Println("listen"+address)
	//defer延迟关闭侦听器
	defer l.Close()
	//循环侦听
	for {
		//新连接没进来时, Accept是阻塞
		conn,err := l.Accept()
		//发现任何侦听错误都进行报告打印
		if err != nil {
			fmt.Println(err.Error())
			continue
		}
		//根据连接开启会话,这个过程需要并发执行
		go handleSession(conn,exitChan)
	}
}	

第七行接受连接的入口,传入地址信息参数和退出服务用的通道参数
第九行使用net包的Listen()函数对传入的地址进行侦听。
第十一到十三行如果侦听发生错误打印错误报告,并使用通道写入非零值退出服务器。
第十六行表示侦听成功,打印侦听地址
第十八行使用defer关键字将服务器延迟退出(知道函数结束退出)
第二十行循环侦听
第二十二行服务器接受一个连接,在没有连接时,Accept函数会一直阻塞,直到连接到来。
第二十四到第二十六行发生任何侦听错误都打印并跳过这次循环。
第二十九行每个连接都会产生一个会话,会话的处理与接受逻辑需要并发执行。

会话处理
每个连接的会话就是一个接收数据的循环。当没有数据时,调用reader.ReadString会发生阻塞,等待数据的到来。一旦数据到来,就可以进行各种逻辑处理。
Telnet会话处理代码

package main
import(
	"bufio"
	"fmt"
	"net"
	"strings"
)
//连接的会话逻辑
func handleSession(conn net.Conn, exitChan chan int) {
	fmt.Println("Session start:")
	//创建一个网络连接数据的读取器
	reader := bufio.NewReader(conn)
	//接收数据的循环
	for {
		//读取字符串直到碰到回车返回
		str,err := reader.ReadString('/n')
		//数据读取正确
		if err == nil {
			//去掉字符串尾部的回车
			str = strings.TrimSpace(str)
			//处理Telnet命令
			if !processTelnetCommand(str,exitChan) {
				conn.Close()
				break
			}
			//Echo 逻辑,返回接收的数据
			conn.Write([]byte(str+"\r\n"))
		} else {
			//发生错误
			fmt.Println("Session closed")
			conn.Close()
			break
		}
	}
}

第九行会话入口,传入连接和退出用的通道
第十二行使用bufio包的NewReader()方法创建一个网络数据读取器,这个Reader将输入数据的读取过程进行封装,方便我们快速获取到需要的数据。
第十四行会话处理开始,从Socket连接,通过reader读取器读取封包,处理封包后需要继续读取从网络发送过来的下一个封包,因此需要一个会话处理循环。
第十六行使用reader.ReadString()方法进行封包读取。内部会自动处理粘包过程,直到下一个回车符到达后返回数据。这里认为封包来自Telnet,每个指令以回车换行符(“\r\n”)结尾。
第十八行数据读取正常时返回err为nil,如果发生连接断开或者接收错误等网络错误时err就会返回信息。
第二十行使用strings包下的TrimSpace()函数处理数据尾部的回车和空白符。
第二十二行将str字符串传入Telnet指令处理函数processTelnetCommand()中,同时传入退出控制通道exitChan。当这个函数返回false时,表示需要关闭当前连接。
第二十七行将有效数据通过conn的Write()方法写入,同时在字符串尾部添加回车符(“\r\n”),数据将会被Socket发送给连接方。
第二十八到第三十四行,当reader.ReadString()发生错误时,打印错误并关闭连接。

Telnet命令处理
Telnet是一种协议,在操作系统上可以在命令行使用Telnet命令发起TCP连接。
Telnet命令处理代码

package main
import(
	"fmt"
	"strings"
)
func processTelnetCommand(str string, exitChan chan int) bool {
	//@close指令表示终止本次对话
	if strings.HasPrefix(str, "@close") {
		fmt.Println("Session closed")
		//告诉外部需要断开连接
		return false
	}
	//@shutdown指令表示终止服务进程
	else if strings.HasPrefix(str,"@shutdown") {
		fmt.Println("Session shutdown")
		//往通道中写入0阻塞等待接收方处理
		exitChan <- 0
		return false
	}
	//打印输出字符串
	fmt.Println(str)
	return true
}

第六行,处理Telnet命令的函数入口,传入有效字符串并退出通道。
第八到十一行,当输入字符串包含“@close“前缀时,在第十一行返回false,表示需要关闭当前会话。
第十四到第十八行当输入字符串包含”@shutdown“前缀时,第十七行向通道中输入0表示结束服务器。
第二十一行,没有特殊的控制字符时,打印输入的字符串。

程序入口

package main
import "os"

func main(){
	//创建无缓冲阻塞通道
	exitChan := make(chan int)
	//将服务器并发运行
	go server("127.0.0.1:7001",exitChan)
	//通道阻塞等待接收返回值
	code := <- exitChan
	//标记程序返回值并退出
	os.Exit(code)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言学习笔记.pdf》是一本关于Go语言学习学习笔记,内容丰富且简洁明了。本书从基础知识开始,逐步介绍了Go语言的语法、特性和常用库函数等。在学习笔记中,作者通过实际的示例和练习帮助读者理解Go语言的概念和用法。 第一章介绍了Go语言的起源和发展,为读者提供了对Go语言背景的整体了解。第二章讲解了Go语言的基本语法,例如变量声明、循环和条件语句等。通过大量的代码示例,读者能够更好地理解Go语言的语法和结构。 接下来的章节重点介绍了Go语言的并发编程和高级特性。第三章详细介绍了Go语言中的goroutine和channel,这是Go语言并发编程的核心机制。作者通过生动的示例代码和实际应用案例,向读者展示了如何使用goroutine和channel实现并发编程。 第四章和第五章分别介绍了Go语言中的面向对象编程和函数式编程。通过深入讲解Go语言中的结构体、接口和函数,读者能够更好地应用这些特性进行代码设计和开发。 最后几章则介绍了Go语言中常用的库函数和工具。例如,第六章介绍了Go语言中用于网络编程的net包和http包。读者可以学习到如何使用这些库函数构建基于网络的应用程序。 总的来说,《Go语言学习笔记.pdf》是一本非常实用的Go语言学习资料。通过阅读这本书,读者能够系统地学习和理解Go语言的基本概念和高级特性,为之后的Go语言开发打下坚实的基础。无论是初学者还是有一定编程经验的开发者,都能从中获得丰富的知识和经验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值