- IP+Port 可以确定一个程序
- 数据通信,需要建立一个Socket
1、Socket
英文含义:插座,插孔。在网络通信过程中,需要两端,成对出现。
一般称之为套接字,用于描述IP地址和端口。可以实现不同程序之间的数据通信。
双向半双工: 对讲机****———Channel
双向全双工: 电话——–Socket
单工通信: 遥控器——
2、网络应用程序设计模式
- C/S 模式
- 传统的网络应用设计模式,客户机(client)/ 服务器(server)模式。需要在通信两端个字部署客户机和服务器完成数据通信。
- B/S 模式
- 浏览器(Brower)/ 服务器(Server)模式。只需在一段部署服务器,而另外一段使用每台PC默认配置的浏览器即可完成数据的传输。
- 优缺点:
- c/s模式: 客户端位于目标主机上,可以保证性能,将数据缓存至客户端本地,从而提高数据传输效率。
- 可在标准协议的基础上根据需求裁剪和定制。 腾讯的通信协议。
- **b/s模式: **没有客户端,使用标准浏览器作为客户端,其工作开发量较小。
- 协议选择不灵活
- 网络应用支持受限
- 缓存数据不尽如人意,在线缓存,用户体验差
- c/s模式: 客户端位于目标主机上,可以保证性能,将数据缓存至客户端本地,从而提高数据传输效率。
TCP通信
- 面向连接的,可靠的数据包传输
TCP 的 C/S架构
Go语言开发主要是C/S架构
- TCP:建立好连接,再进行传递。—————— 打电话,保证畅通才行。
- UDP:不建立连接,直接进行传递。—————电报/发短信,只要有地址就可以。
![QQ截图20210826134348.png](resources/A642E2154701437295956D6712779A03.png =673x635)
** TCP服务器**
- net.Listen() 设置服务器的监听资源 *选择UDP或TCP ,设置IP+Port*
- Accept() 阻塞等待用户链接(真正等待监听) 返回Socket,用于通信的Socket
- Read() 读取客户端发送来的数据请求
- Write() 回写,数据应答。处理请求
- Close() 关闭连接
** TCP客户端**
- net.Dial() 拨号,请求连接. 返回Socket,用于通信的Socket
- Write() 发送请求数据
- Read() 读取来自服务端的回写数据
- Close() 关闭连接
⚠️注意点:
- ** 一般需要先启动服务器!**
- ** 数据通信,Socket需要两个成对存在。**
- **另外 **net.Listen() 也创建出了一个Socket,目的是绑定IP地址和Port端口号。
- 用于创建Socket的Socket
- 等待另外的客户端连接上来时,再创建Socket
- 一次Socket通信过程中,客户端和服务器一共创建了3个Socket,参与数据通信的有2个,剩下的1个用于绑定IP地址和Port端口号,设置监听。
![QQ截图20210826155815.png](resources/BC50E8A013DEC61770D8F443BF959F00.png =1207x397)
TCP-CS服务器:
- 创建监听套接字 listener:=net.Listen(“TCP”,”IP+Port”) IP+Port. ——服务器自己的IP和Port
- 启动监听连接 conn:=listener.Accept() 返回用于通信的socket–conn
- Conn.Read()
- 处理使用数据
- Conn.Write(()
- 关闭conn、listner
TCP-CS客户端:
- Conn,err:=net.Dial(“TCP”,”服务器的IP+服务器的端口Port”)
- 写数据给服务器 conn.Write()
- 读取服务器回发的数据 conn.Read()
- 关闭 conn.Close()
01、TCP-CS并发服务器:
- 创建监听套接字 listener:=net.Listen(“TCP”,”IP+Port”) IP+Port. ——服务器自己的IP和Port
- for循环 阻塞监听客户端连接事件 conn:=listener.Accept()
- 创建go程,对应每一个客户端进行数据通信。go HandlerConnect()
- 实现HandlerConnect(conn net.Conn)
- 完成之后关闭defer conn.Close
- 获取成功连接客户端的ip地址. Conn.RemoteAddr()
- for 循环 读取客户端发送的数据 conn.Read()
- 处理数据
- 回写 conn.Write()
服务器判断关闭:
- 非正常关闭
- Read() 读客户端,返回0—————-来判断对端关闭!
- 正常关闭
- 使用nc命令发送数据时,默认末尾会加“\n”
02、TCP通信过程:
TCP连接建立断开包含三次握手Three-Way Handshake(建立连接的过程),四次挥手(断开连接的过程)。—–底层
一次TCP通讯的时序图。
![QQ截图20210830111131.png](resources/7F047BFF2E3019E61373647EF855E154.png =670x710)
三次握手:
- 主动发起请求端,发送SYN标识位 mss(滑动窗口): 1460 数据容量上限
- 被动建立连接请求端,应答ACK 同时发送SYN
- 主动发起请求端,发送应答 ACK
标志TCP三次握手建立完成。————server: Accept() 返回。 ———client: Dial() 完成
四次挥手:
- 主动关闭连接请求端,发送FIN
- 被动关闭连接请求端,应答ACK ———标志,半关闭完成。 ————其中一个调用了close()
- 被动关闭连接请求端,发送FIN
- 主动关闭连接请求端,应答ACK ———标志,四次挥手建立完成。 ————另一个也调用了close()
03、TCP状态转换图:
作用:
- **利用命令查看进程的工作状态,了解服务器处于通信的哪个阶段,判断处于该阶段易发生的错误而进行排查。 **established建立了
![TCP状态转换图.png](resources/4390D840AD31936113747C1C067364CE.png =816x1152)
- 主动发起连接请求端
- Closed—-完成三次握手——Established(数据通信状态)—-Dial()函数返回
- 被动发起连接请求端
- Closed——调用Accept()——Listen——完成三次握手—-Established(数据通信状态)—–Accept()函数返回
- 数据传递期间
- 一直是Established(数据通信状态)
- 主动关闭连接请求端
- Established(数据通信状态)——FIN_WAIT2(半关闭状态)——TimeWait———2MSL——确认最后一个ACK被对端成功接收————Closed
- 被动关闭连接请求端
- Established(数据通信状态)—-closed
04、TCP状态转换—-程序运行状态对应
- 查看状态命令
- Netstat -an
UDP通信
- 无连接,不可靠的报文传递。
- 应用端需要封装校验协议比较。
- 并发数量多时应用
![UDP.png](resources/BDE01863164E6ECC84CBF59EDF49EDDE.png =898x456)
01、UDP-CS服务器
- 创建Server端地址结构(IP+Port)net.ResolveUDPAddr()
- 创建用于通信的Socket,绑定地址结构 udpConn=net.ListenUDP()
- 读取客户端发送的数据 n,clientAddr,err=ReadFromUDP()
- 写数据给客户端 WriteToUDP(“代写数据”,clientAddr)
- 关闭通信的Socket
02、UDP-CS客户端
- Net.Dial(“udp”,server端IP+端口)
- 写数据给服务器 conn.Write()
- 读取服务器回发的数据 conn.Read()
- 关闭 conn.Close()
03、UDP-CS并发服务器
- UDP默认支持客户端并发访问
- 使用 go 程 将 服务器处理 ReadFromUDP 和 WriteToUDP操作分开。提高并发效率。
04、UDP与TCP的差异
![UDP迅雷.png](resources/36BC106741E42F690751B9ED255E5B14.png =898x456)
优点: TCP: UDP:
稳定、安全、有序。 效率高、开销小。开发复杂度低。
缺点: TCP: UDP:
效率低、开销大。开发复杂度高。 稳定性差、安全低、无序。
使用场景:
TCP:对数据传输安全性、稳定性要求较高的场合。 网络文件传输。下载、上传。
UDP:对数据实时传输要求较高的场合。视频直播、在线电话会议。游戏
![QQ截图20210831152906.png](resources/7BE653ED28C3031BE9C0A39415281B06.png =970x311)
网络文件传输练习
- 结合I/O,文件读写操作复习
![网络文件传输.png](resources/DB3512FCAC2E2D679361F54085E0C3BE.png =1347x684)
01、获取文件属性:
fileInfo:os.stat(文件访问绝对路径) fileInfo 接口,两个接口。 Name() 获取文件名。 Size() 获取文件大小。
02、 文件传输——发送端(客户端):
1. 提示用户使用命令行参数输入文件名。接收文件名 filepath(含访问路径)
2. 使用 os.Stat()获取文件属性,得到纯文件名 fileName(去除访问路径)
3. 主动发起连接服务器请求,结束时关闭连接。
4. 发送文件名到接收端 conn.Write()
5. 读取接收端回发的确认数据 conn.Read()
6. 判断是否为“ok”。如果是,封装函数 SendFile() 发送文件内容。传参 filePath 和 conn
7. 只读 Open 文件, 结束时Close文件
8. 循环读本地文件,读到 EOF,读取完毕。
9. 将读到的内容原封不动 conn.Write 给接收端(服务器)
03、文件传输——接收端(服务器):
1. 创建监听 listener,程序结束时关闭。
2. 阻塞等待客户端连接 conn,程序结束时关闭conn。
3. 读取客户端发送文件名。保存 fileName。
4. 回发“ok”。
5. 封装函数 RecvFile 接收客户端发送的文件内容。传参 fileName 和 conn
6. 按文件名 Create 文件,结束时 Close
7. 循环 Read 发送端网络文件内容,当读到 0 说明文件读取完毕。
8. 将读到的内容原封不动Write到创建的文件中
发送端:
1 | package main |
接收端:
1 | package main |
- 本文作者: 梁俊可
- 本文链接: http://ljk3d.com/2021/10/19/goLangNote/goLangAdvance/02_GoLang语言正式课_Go网络编程_Socket编程/
- 版权声明: 梁俊可工作室