开发者学堂课程【Go语言核心编程 - 面向对象、文件、单元测试、反射、TCP编程:TCP 编程-服务器监听】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/626/detail/9779
TCP编程-服务器监听
内容介绍
一、top socket 编程的快速入门
二、服务器监听代码
三、Telnet 测试端口连接
一、top socket编程的快速入门
快速入门应用实例
1.程序框架图示意图:
正常情况下此程序应该各写一端,但是一台电脑,所以这台电脑既是客户端又是服务器端,写完后启动服务器,发消息都可以接收到,就是一个简单的通讯。理论上应该先写服务器端
2.服务器端功能:
(1)编写一个服务器端程序,在8888端口监听
(2)可以和多个客户端创建链接
(3)链接成功后,客户端可以发送数据,服务器端接受数据,并显示在终端上
(4)先使用 telnet 来测试,然后编写客户端程序来测试
二、服务器监听代码
打开 vscode,新建一个文件夹 chapter18,tcpdemo 里面有 client 和 server,在实际开发中 client 和 server 运行在不同的电脑中,server 下设置 server.go,开始书写代码:
1.代码
package main
import(
"fmt"
"net”//做网络socket开发时,net包含有我们需要所有的方法和函数
)
func main() {
fmt.Println("服务器开始监听...")
//net.Listen("tcp","0.0.0.0:8888")
//1.tcp表示使用网络协议是tcp
//2.0.0.0.0:8888 表示在本地监听 8888端口
listen, err :=net.Listen("tcp", "0.0.0.0:8888")
if err != nil {
fmt.Println("listen err=", err)
return
}
fmt.Printf("listen suc=%v\n", listen)
}
2.net
打开文档查看 net 包究竟是什么
net 包提供了可移植的网络 I/O 接口,包括 TOP/IP、UDP、域名解析和 Unix 域 socket
3.Listen 函数
经典函数:Listen 函数创建的服务端
func Listen
func Listen(net,laddr string)(Listen,erro)
返回在一个本地网络地址 laddr 上监听的 listener 网络类型参数 net 必须是面向流的网络:
"tcp"、"tcp4",tcp6"、"unix"或"unixpacker"。参见 Dial 函数获取 laddr 的语法
net 中添的的是按照什么写译填写,tcp,tcp6等这里显示用的是 tcp 型,laddr string 是地址代表在哪个 ip 的哪个端口进行监听,如果监听成功会返回 listen,失败会返回 erro。listen 是什么?,点进查看,type Listener interface {
// Addr 返回该疫口的网络地址
Addr()Addr
//Accept 等待并返回下一个连接到该接口的连接
Accept() (c Conn, err error)
//close 关闭该接口,并使任何阻塞的 Accept 操作都会不再阻塞并返回错误。
Close()error
}
Listener 是一个接口,一旦连接成功通过 listener 可以得到网络地址,还可以通过 listener accept,用完过后要保证close 了
对代码的解释:监听使用的是 net 包中的 listen,参数为 tcp,也就是通话依靠 tcp 协议。127.0.0.1:8888的意思是在本地监听8888端口,如果代码没有问题会看到有一个8888在监听,0.0.0.1:8888这种写法也可以,此讲用0.0.0
4.代码运行效果
现在切换到目录模式,跑代码,查看效果如下:
D:\go project\src\go_code\chapter18\tcpdemo\server>go run Server.go
服务器开始监听......
listen suc=8<0xc04208c000>
D:\go project\src\go_code\chapter18\tcpdemo\server>
这个刚监听就跑路了,为了保证一直监听的状态,要靠 Accept 函数,等待连接,没有连接就一直等待,等待连接是一个 for 循环,在 return 后加入
5.修改代码
defer listen.close()//延时关闭 listen
//循环等待客户端来链接我
for {
//等待客户端链接
fmt.Println("等待客户端来链接....")
conn, err := listen.Accept()
if err != nil {
fmt.Println("Accept()err=",err)
} else {
fmt.Printf("Accept()suc con=%v\n”,conn)
}
//这里准备其一个协程,为客户端服务
Accept 刚好返回一个 conn,conn 是实现 conn 接口的变量或者是实例可以读、写、close、拿到自己的地址、对方的地址。可以通过网络阻止哪些服务器连接,例如阻止以192168开头的都要拒绝,accept 查看地址不对直接 close。所以 tcp 编程比 htp 编程痛快,因为 htp 这些协议都看不到
6.Conn
type Conn interface {
//Read 从连接中读取数据
//Read 方法可能会在超过某个固定时间限制后超时返回错误,该错误的 Timeout()方法返回真
Read(b []byte)(n int,err error)
// write 从连接中写入数据
//write 方法可能会在超过某个固定时间限制后超时返回错误,该错误的 Timeout()方法返回真
Write(b []byte) (n int,err error)
//Close 方法关闭该连接
//并会导致任何阻塞中的 Read 或 write 方法不再阻塞并返回错误
Close() error
//返回本地网络地址
LocalAddr()Addr
//返回远端网络地址
RemoteAddr()Addr
//设定该连接的读写 deadline,等价于同时调用 SetReadDeadline和SetwriteDeadline
//deadline 是一个绝对时间,超过该时间后 I/0 操作就会直接因超时失败返回而不会阻塞
//deadline 对之后的所有 I/O 操作都起效,而不仅仅是下一次的读或写操作
//参数t为零值表示不设置期限
SetDeadline(t time.Time) error
//设定该连接的读操作 deadline,参数 t 为零值表示不设置期限
SetReadDeadline(t time.Time) error
//设定该连掖的写操作 deadline,參数 t 为零值表示不设置期限
//即使写入超时,返回值 n 也可能>日,说明成功写入了部分数据
SetwriteDeadlinett time.Time) error
}
代码解释:accept 出错不需要 return,因为 A 客户端出错,B 客户端未必出错,所以不需要 return。accept 成功后就会回到等待客户端来连接,协程可以理解为上述程序框架图
测试更改后代码是否成功:
最简单的方法是写一个客户端,另一个方法是 telnet 测试
三、telnet 测试端口连接
telnet 可以测试端口是否在连接,例如连接到 baidu.com
D:\goproject\src\go_code\chapter18\tcpdemo\server>telnet www.baidu.com 80
回车显示
正在连接到 www.baidu.com...
说明百度服务器确实由80连接
输入 control➕[]退出此页
现在使服务器端运作起来查看是否连接成功,
D:\go project\src\go_code\chapter18\tcpdemo\server>go run Server.go
服务器开始监听...
等待客户端来连接...
此时卡在了 Accept 处等待链接,现在连接它
Accept<>suc con=&<<0xc042086240>>
等待客户端连接...
连接后还是在等待
cmd 再连接下
C:\Users\Administrator>telnet 127.0.0.1 8888
因为是本地所以输入127,但是你们要查看我的 ip 地址
Accept<>suc con=&<<0xc042086480>>
等待客户端连接...