Go语言网络编程

网络协议

从应用的角度出发,协议可以理解为"规则",是数据传输和数据解释的规则。

假设,A和B双方要传输文件,现规定:

  • 第一步,传输文件名,接收文接收到文件名,响应OK给传输方;
  • 第二步,发送文件的尺寸,接收方接收到该数据再次响应一个OK;
  • 第三步,传输文件内容,同前两步一样,接收方接收数据完成后响应OK表示文件内容接收成功。

由此,无论A和B之间传递何种文件,都是通过三次数据传输来完成。A和B之间形成了一个最简单的数据传输规则。

双方都按此规则发送和接收数据。A和B之间达成的这个相互遵守的规则即为协议。

这种仅在A和B之间被遵守的协议称之为原始协议。

当此协议被更多的人采用,不断的增加,改进,维护和完善,最终形成一个稳定,完整的文件传输协
议,被广泛应用于各种文件传输过程中。

该协议就成为一个标准协议。最早的FTP协议就是由此衍生而来的。

分层模型

网络分层架构

为了减少协议设计的复杂性,大多数网络模型均采用分层的方式来组织。

每一层都有自己的功能,就像建筑物一样,每一层都靠下面一层支持。每一层利用下一层提供的服务来为上一层提供服务,本层服务的实现细节对上层屏蔽。

OSI七层模型:

  • 应用层
  • 表示层
  • 会话层
  • 传输层
  • 网络层
  • 链路层
  • 物理层

TCP/IP模型:

  • 链路层
  • 网络层
  • 传输层
  • 应用层

越下面的层,越靠近硬件,越上面的层,越靠近用户。

物理层:主要定义物理设备标准,如网线的接口类型,光纤的接口类型,各种传输介质的传输速率等。其主要作用是传输比特流(就是由0和1转化成的电流强弱来进行传输,到达目的地后再转化成0和1,也就是我们常说的数模转换与模数转换)。这一层的数据叫做比特。

数据链路层:定义了如何让格式化数据以帧为单位进行传输,以及如何让控制对物理介质的访问。这一层通常还提供错误检测和纠正,以确保数据的可靠传输。

网络层:在位于不同地理位置的网络中的两个主机系统之间提供连接和路径选择。Internet的发展使得从世界各站点访问信息的用户数大大增加,而网络层正是管理这种连接的层。

传输层:定义了一些传输数据的协议和接口号,比如WWW服务的端口号是80。TCP(传输控制协议,传输效率低,可靠性强,用于传输可靠性要求高,数据量大的数据),UDP(用户数据报协议,与TCP特性恰恰相反,用于传输可靠性要求不高,数据量小的数据,比如QQ聊天数据就是通过这种方式传输的)。这一层的数据叫做比特。其主要是将下层接收的数据进行分段和传输,到达目的地址后再进行重组,常常把这一层数据叫做段。

会话层:通过传输层(端口号:传输端口与接收端口)建立数据传输的通路。主要在系统之间发起会话请求或者接受会话请求(设备之间需要互相认识,可以是IP地址,也可以是MAC地址或者是主机名)

表示层:可确保一个系统的应用层所发送的信息可以被另一个系统的应用层读取。

应用层:网络软件

层与协议

1
2
3
4
链路层:ARP,RARP
网络层:ICMP,IGMP
传输层:TCP,UDP
应用层:FTP,NFS,Telnet,SFTP,TFTP

Socket编程

什么是Socket

Socket起源于Unix,而Unix基本哲学思想之一就是"一切皆文件",Unix上所有的文件都可以用"打开
open -> 读写write/read -> 关闭close"模式来操作。

Socket就是该模式的一个实现,网络的Socket数据传输是一种特殊的I/O,Socket也是一种文件描述
符。

Socket也具有一个类似于找开文件的函数调用:Socket(),该函数返回一个整型的Socket描述符,随后的连接建立,数据传输等操作都是通过该Socket实现的。

常用的Socket类型有两种:流式Socket(SOCK_STREAM)和数据报式Socket(SOCK_DGRAM)。流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。

TCP的架构

  • B/S架构:浏览器/服务端架构
  • C/S架构:客户端/服务端架构

示例代码

服务端程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import (
"net"
"fmt"
)

func main() {
//监听
listener, err := net.Listen("tcp", "127.0.0.1:8000")
if err != nil {
fmt.Println("err = ", err)
return
}
defer listener.Close()
//阻塞等待用户链接
conn, err := listener.Accept()
if err != nil {
fmt.Println("err = ", err)
return
}
//接收用户的请求
buf := make([]byte, 1024) //1024大小的缓冲区
n, err1 := conn.Read(buf)
if err1 != nil {
fmt.Println("err1 = ", err1)
return
}
fmt.Println("buf = ", string(buf[:n]))
defer conn.Close() //关闭当前用户链接
}

客户端程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import (
"fmt"
"net"
)

func main() {
//主动连接服务器
conn, err := net.Dial("tcp", "127.0.0.1:8000")
if err != nil {
fmt.Println("err = ", err)
return
}
defer conn.Close()
//发送数据
conn.Write([]byte("are u ok?"))
}

欢迎关注我的其它发布渠道