【Go基础】Socket和WebSocket编程

本文详细介绍了Socket编程的基础,包括TCP和UDP协议的理解,以及在Go语言中如何实现TCP和UDP的客户端和服务端编程。接着,文章探讨了WebSocket协议,解释了其与HTTP的异同,并展示了如何在Go中使用gorilla/websocket库实现WebSocket服务器和客户端。最后,文中提到了WebSocket在实时应用中的重要性和应用场景。
摘要由CSDN通过智能技术生成

一、Socket编程

1. 网络通信过程

  • DMA:网卡和磁盘数据拷贝到内存流程比较固定,不涉及到运算操作,且非常耗时,在磁盘嵌入一个DMA芯片,完成上述拷贝工作,把CPU解脱出来,让CPU专注于运算
  • mmap:用户空间和内核空间映射同一块内存空间,从而达到省略将数据从内核缓冲区拷贝到用户空间的操作,用户空间通过映射直接操作内核缓冲区的数据

阻塞式网络I/O

在这里插入图片描述

非阻塞式网络I/O
在这里插入图片描述

多路复用网络I/O
在这里插入图片描述

socket把复杂的传输层协议封装成简单的接口,使应用层可以像读写文件一样进行网络数据的传输

在这里插入图片描述

socket通信过程
在这里插入图片描述

2. TCP CS架构

2.1 网络通信模型

OSI参考模型

在这里插入图片描述

TCP/IP模型

在这里插入图片描述

传输层数据大小的上限为MSS(Maximum Segment Size, 最大分段大小),网络接口层数据大小的上限为MTU(Maximum Transmit Unit, 最大传输单元)

2.2 TCP协议解读

MSS=MTU-ip首部-tcp首部,MTU视网络接口层的不同而不同,TCP在建立连接时通常需要协商双方的MSS值,应用层传输的数据大于MSS时需要分段

在这里插入图片描述

TCP首部
在这里插入图片描述

  • 前20个字节是固定的,后面还4N个可选字节(TCP选项)
  • 数据偏移:TCP数据部分距TCP开头的偏移量(一个偏移量是4个字节, TCP选项占4N个字节),亦即TCP首部的长度,所以TCP首部的最大长度是15*4=60个字节,即TCP选项最多有40个字节
  • 端口在tcp层指定,ip在IP层指定。端口占2个字节,则最大端口号为2^16-1=65535
  • 由于应用层的数据被分段了,为了在接收端对数据按顺序重组,需要为每段数据编个“序号”
  • TCP规定在连接建立后所有传送的报文段都必须把ACK设置为1

TCP建立连接
在这里插入图片描述

  • 第一次握手:TCP首部SYN=1,初始化一个序号=J。SYN报文段不能携带数据
  • 第二次握手:TCP首部SYN=1,ACK=1,确认号=J+1,初始化一个序号=K,此报文同样不携带数据
  • 第三次握手:SYN=1,ACK=1,序号=J+1,确认号=K+1。此次一般会携带真正需要传输的数据
  • 确认号:即希望下次对方发过来的序号值
  • SYN Flood 攻击始终不进行第三次握手,属于DDOS攻击的一种

TCP释放连接
在这里插入图片描述

  • TCP的连接是全双工(可以同时发送和接收)的连接,因此在关闭连接的时候,必须关闭传送和接收两个方向上的连接
  • 第一次挥手:FIN=1,序号=M
  • 第二次挥手:ACK=1,序号=M+1
  • 第三次挥手:FIN=1,序号=N
  • 第四次挥手:ACK=1,序号=N+1
  • 从TIME_WAIT进入CLOSED需要经过2个MSL(Maxinum Segment Lifetime),RFC793建议MSL=2分钟

2.3 Go TCP编程

  • 用三元给(ip地址,协议,端口号)唯一标示网络中的一个进程,如(172.122.121.111, tcp, 5656)
  • IPv4的地址位数为32位,分为4段,每段最大取值为255
  • IPv6的地址位数为128位,分为8段,各段用16进制表示,最大取值为ffff
  • 端口:0 ~ 1023 被熟知的应用程序占用(普通应用程序不可以使用),49152 ~ 65535客户端程序运行时动态选择使用
func ResolveTCPAddr(net, addr string) (*TCPAddr, os.Error)

net参数是“tcp4”、“tcp6”、“tcp”中的任意一个,分别表示TCP(IPv4-only),TCP(IPv6-only)或者TCP(IPv4,、IPv6的任意一个),addr表示域名或者IP地址,例如" www.qq.com:80" 或者"127.0.0.1:22"

func DialTCP(network string, laddr, raddr *TCPAddr) (*TCPConn, error)

network参数是"tcp4"、“tcp6”、"tcp"中的任意一个,laddr表示本机地址,一般设置为nil,raddr表示远程的服务地址

func net.DialTimeout(network string, address string, timeout time.Duration) (net.Conn, error)

创建连接时设置超时时间

func (*net.conn) Write(b []byte) (int, error)

通过conn发送数据

func (net.Conn).Read(b []byte) (n int, err error)

从conn里读取数据,如果没有数据可读,会阻塞

func ioutil.ReadAll(r io.Reader) ([]byte, error)

从conn中读取所有内容,直到遇到error(比如连接关闭)或EOF

func ListenTCP(network string, laddr *TCPAddr) (*TCPListener, error)

监听端口

func (l *TCPListener) Accept() (Conn, error)

阻塞,直到有客户端请求建立连接

func (*net.conn) Close() error

关闭连接

func (c *TCPConn) SetReadDeadline(t time.Time) error 
func (c *TCPConn) SetWriteDeadline(t time.Time) error

设置从一个tcp连接上读取和写入的超时时间

func (c *TCPConn) SetKeepAlive(keepalive bool) os.Error

当一个tcp连接上没有数据时,操作系统会间隔性地发送心跳包,如果长时间没有收到心跳包会认为连接已经断开

tcp_server.go

package main

import (
	"encoding/json"
	"fmt"
	"go-course/socket"
	"net"
	"strconv"
	"time"
)

type (
	Request struct {
   
		A int
		B int
	}
	Response struct {
   
		Sum int
	}
)

func handleRequest2(conn net.Conn) {
   
	conn.SetReadDeadline(time.Now().Add(30 * time.Second)) // 30秒后conn.Read会报出i/o timeout
	defer conn.Close()
	// 长连接,即连接建立后进行多轮的读写交互
	for {
   
		requestBytes := make([]byte, 256) // 初始化后byte数组每个元素都是0
		read_len, err := conn.Read(requestBytes)
		if err != nil {
   
			fmt.Printf("read from socket error: %s\n", err.Error())
			break // 到达deadline后,退出for循环,关闭连接,client再用这个连接读写会发生错误
		}
		fmt.Printf("receive request %s\n", string(requestBytes)) // []byte转string时,0后面的会自动被截掉

		var request socket.Request
		json.Unmarshal(requestBytes[:read_len], &request) // json反序列化时会把0都考虑在内,所以需要指定只读前read_len个字节
		response := socket.Response{
   Sum: request.A + request.B}

		responseBytes, _ := json.Marshal(response)
		_, err 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ricky_0528

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值