golang并发编程-01多进程编程-04socket
@
1. 基本特性
1.1 声明
int socket(int domain, int type, int protocol);
1.1.1 三个接收参数
- 通讯域
- 类型
- 所用协议。
1)通讯域
- “AF”是address family的缩写,意为地址族
- IPv4域和IPv6域的通讯是在网络范围内的,而Unix域的通讯则是在单台计算机范围内的
2)类型
- 两种数据形式 和 数据边界
1)数据报
数据接收方的Socket接口程序可以意识到数据的边界并会对它们进行切分。
2)字节流
实际上传输的是一个字节接着一个字节的串。
SOCK_SEQPACKET类型的Socket:
- 数据发送方的Socket接口程序记录数据边界,并将其信息随着字节流一同被发往数据接收方。
- 数据接收方的Socket接口程序会根据数据边界把字节流切分成若干个字节流片段,并按照需要依次传递给应用程序。
- 逻辑连接
1)有连接的Socket
数据传输之前必须要先建立逻辑连接
传输数据的时候不必再指定目标地址(连接已经指明了双方的地址)
2)无连接的Socket
在进行通讯时无需建立连接。
每一个数据包都是独立的
数据包中都含有目标地址(因此每个数据包都可能被传输至不同的目的地)
3)使用的协议
一般会把0作为它的第三个参数值。其含义是让操作系统内核根据第一个参数和第二个参数的值自行决定Socket所使用的协议。
TCP/IP协议栈中的传输层协议
- TCP(Transmission Control Protocol)传输控制协议
- UDP(User Datagram Protocol)用户数据报协议
- SCTP(Stream Control Transmission Protocol)流控制传输协议
TCP/IP协议栈中的网络互连层协议
- IPv4(Internet Protocol v4)译作网际协议第四版
- IPv4(Internet Protocol v6)译作网际协议第六版
1.1.2 socket的返回值
一个int类型的值。该值是作为socket唯一标识符的文件描述符。
1.2 基于TCP/IP协议栈的Socket通讯
1.2.1 通讯流程
1.2.2 go语言实现
主要会使用到标准库代码包net中的API。
1)获取监听器
- 使用函数:
func Listen(net, laddr string) (Listener, error)
示例:
listener, err := net.Listen("tcp", "127.0.0.1:8085")
- 第一个参数 net
含义:以何种协议来在给定的地址上监听。必须是面向流的协议。
TCP和SCTP都属于面向流的传输层协议,但不同的是:
- TCP协议实现程序无法记录和意识到任何消息边界,也无法从字节流分离出消息
- SCTP协议实现程序却可以做到这些的
- 第二个参数 laddr
含义:当前程序在网络中的标识
格式:“host:port” (如:127.0.0.1:1840
)
“host”代表IP地址或主机名
“port”则代表当前程序欲监听的端口号
- 第一个返回值
即是我们需要的监听器
类型:net.Listener
2)等待连接接入
conn, err := listener.Accept()
-
效果
流程会被阻塞,直到某台计算机上的某个应用程序与当前程序建立了一个TCP连接。 -
返回值
第一个返回值代表 当前TCP连接的net.Conn类型值
3)向某个地址发送数据(如客户端向服务器发起)
- 语法
func Dial(network, address string) (Conn, error)
示例:
conn, err := net.Dial("tcp", "127.0.0.1:8085")
- 参数
- 第一个(network)
和net类似(可以参考“1) 获取监听器”中net
参数),但种类更多(因为不需要建立连接)
因此,udp、udp4、udp6、ip, ip4和ip6都可以作为参数- 第二个(address)
对方地址,如:127.0.0.1:8080
4)设置超时时间
func DialTimeout(network, address string, timeout time.Duration) (Conn, error)
timeout默认是纳秒,因此我们一般改成秒,使用如下:
conn, err = net.DialTimeout("tcp", "127.0.0.1:8085", 2*time.Second)
1.3 net.Conn接口使用
1.3.1 Read方法
-
作用:
用来从Socket的接收缓冲区中读取数据 -
方法声明
Read(b []byte) (n int, err error)
-
参数
[]byte类型。
该参数的值相当于一个被用来存放从连接上接收到的数据的“容器”
它的长度完全由应用程序来决定。 -
使用示例
var dataBuffer bytes.Buffer
b := make([]byte, 10)
for {
n, err := conn.Read(b)
if err != nil {
if err == io.EOF {
fmt.Println("The connection is closed.")
conn.Close()
} else {
fmt.Printf("Read Error: %s\n", err)
}
break
}
dataBuffer.Write(b[:n])
}
- 数据切分
切分数据:
reader := bufio.NewReader(conn)
获取切分后的数据:
line, err := reader.ReadBytes('\n')
1.3.2 Write方法
- 作用:
向Socket的发送缓冲区写入数据 - 用法
和Read基本相同
Write(b []byte) (n int, err error)
- 创建一个缓存,往里写
writer := bufio.NewWriter(conn)
1.3.3 Close方法
1.3.4 LocalAddr / RemoteAddr 方法
不接受任何参数并返回一个net.Addr类型的结果。
○ 作用
- LocalAddr:返回代表了本地地址的net.Addr类型值
- RemoteAddr:返回代表了远程地址的net.Addr类型值。
○ 返回值 net.Addr
net.Addr 类型是一个接口类型。在它的方法集合中有两个方法法:
- Network 方法
返回当前连接所使用的协议的名称。
示例:
conn.LocalAddr().Network()
- String方法
返回相应的地址
示例:
conn.RemoteAddr().String()
1.3.5 SetDeadline
- 作用
当前连接上的I/O(包括但不限于读和写)操作的超时时间 - 示例
b := make([]byte, 10)
for {
conn.SetDeadline(time.Now().Add(2 * time.Second))
n, err := conn.Read(b)
// 省略若干条语句
}
- 取消超时时间
conn.SetDeadline(time.Time{})
1.3.6 SetReadDeadline / SetWriteDeadline方法
- 作用:
同上,但分别对应读超时和写超时