golang-操作系统-信号量

十二、信号

  1. 操作系统的信号(signal)是ipc进程通信唯一一种异步的通信方式,本质 是用软件来模拟硬件的中断机制。

  2. unix 系统 使用 kill -l 查看支持的信号量。有62种,其中 32,33没有编号。1-31属于标准信号。34-62属于实时信号。

  3. 信号来源有键盘(ctrl +c),硬件故障,系统函数调用,软件非法运算。

  4. 进程响应信号方式,忽略,捕捉,执行默认操作(终止进程,忽略该信号量,终止进程并保存内存,停止进程,)

  5. os/signal中的Notify方法 ,把操作系统发给当前进程的指定信号 通知给该函数的调用方法。

    //1.注册自定义处理的信号量
    signs := make(chan os.Signal)
    signal.Notify(signs, syscall.SIGINT, syscall.SIGQUIT)
    //2.处理定义的信号事件
    for sig := range signs {
    log.Printf("signal:%s",sig.)
    }
    //3.如果收到了没有自定义的信号,会执行操作系统默认操作
    
  6. unix 系统中 sigkill ,sigstop不能被自行处理也不会被忽略,只能是执行系统默认操作。

  7. 通用信号,处理可以自定义处理,还可以在之后恢复 系统默认操作。

    sigRecv1 := make(chan os.Signal, 1)
    	signal.Notify(sigRecv1, syscall.SIGINT, syscall.SIGQUIT)
    
    	sigRecv2 := make(chan os.Signal, 1)
    	signal.Notify(sigRecv2, syscall.SIGQUIT)
    
    	var wg sync.WaitGroup
    	wg.Add(2)
    	go func() {
    		for sig := range sigRecv2 {
    			log.Printf("received a signal sigRecv2:%s\n", sig)
    		}
    		log.Printf("End.[sigRecv2]\n")
    		wg.Done()
    	}()
    	go func() {
    		for sig := range sigRecv1 {
    			log.Printf("received a signal sigRecv1:%s\n", sig)
    		}
    		log.Printf("End.[sigRecv1]\n")
    		wg.Done()
    	}()
    	wg.Wait()
    	/**
    	ctrl + \
    	2022/09/17 22:42:04 received a signal sigRecv2:quit
    	2022/09/17 22:42:04 received a signal sigRecv1:quit
    	*/
    

十三、socket

  1. socket 是ipc进程通信的方式之一,它通过网络连接来使俩个以上的进程建立通信并传递数据。建立了跨主机的进程间通信基础。

  2. linux 操作系统中,存在名为socket的系统调用:int socket(int domain,int type,int protocol) .三个参数分别是通讯域,类型,协议。AF = address family

    1. 通讯域含义地址形式通讯范围
      AF_INETipv4域ipv4地址(4个字节),端口号(2个字节跨主机的应用程序通信
      AF_INET6ipv6域ipv6地址(16个字节),端口号(2个字节)跨主机的应用程序通信
      AF_UNIXUnix域路径名称同台主机的应用程序通信
      特性socket类型
      SOCK_DGRAMSOCK_RAWSOCK_SEQPACKETSOCK_STREAM
      数据形式数据报数据报字节流字节流
      数据边界没有
      逻辑连接没有没有
      数据有序性不保证不保证保证保证
      传输可靠性不具备不具备具备具备
    2. 数据形式,数据报和字节流。数据报有明确的边界。字节流是一个字节接着一个字节的串,没有明确的边界,需要应用程序来处理数据包的边界。

    3. 面向连接的socket 进行数据传输之前必须先建立逻辑连接,在连接被建立后,连接已经暗含了双方的地址,所以传输数据的时候不必再指定目标地址。

    4. 面向无连接的socket通信无语建立连接,传输的每个数据报都是独立的,数据包都含有目标地址,每个数据包可能被传输到不同的目的地址。

    5. 传输可靠性和有序性 与socket 是否面向连接有很大关系,SOCK_RAW 提供网络层 的传输方式。

    6. 通常第三个参数为0,让操作系统根据第一个,第二个参数的值自行决定使用的协议。

      决定因素SOCK_DGRAMSOCK_RAWSOCK_SEQPACKETSOCK_STREAM
      AF_INETUDPIPV4SCTPTCP或SCTP
      AF_INET6UDPIPVIPV6SCTPTCP或SCTP
      AF_UNIX有效无效有效有效
    7. TCP(transmission control protocol),传输控制协议,UDP(user datagram protocol)数据报协议,SCTP(stream control transmission protocol)流传输控制协议。都是tcp/IP协议栈中的传输控制协议。IPV4和IPV6 是网络层协议。

    8. 基于TCP/IP 协议栈的socket通讯

      1. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1uRH7CeG-1666106762425)(C:\Users\xpc\AppData\Roaming\Typora\typora-user-images\image-20220918002351265.png)]

      2. 通过基于tcp/ip 协议栈socket 接口,可以建立和监听tcp连接和udp连接,以及网路层IP协议通信

      3. golang中标准库中提供 listener,err := net.listen(net,laddr string) (Listener,err)

      4. golang, conn,err := listerner.Accept() 阻塞中直到 客户端 与当前程序建立TCP连接。

      5. 通过案例说明 conn客户都与服务端双方的读写操作

        1. 客户端 发送给服务端的每块请求数据都带上数据边界。并切割成数据块。

        2. 客户端获得期望的响应数据后,应该及时关闭连接。

        3. 严格限制耗时,超过5秒超时后 应该报告超时错误并关闭连接。

        4. 服务端 根据事先约定好的数据边界把收到的请求数据切割成数据块

        5. 仅接收可以由int32类型标识的请求数据块,对于不符合要求的数据块,生成错误信息并返回给客户端。处理业务逻辑,发送给客户端的每块响应数据都应该带有约定好的数据边界。

        6. 需要鉴别闲置连接,在过去10秒内,没有任何数据请求的客户端连接。

          const (
          	serverNetwork = "tcp"
          	serverAddress = "127.0.0.1:8085"
          	DELIMITER     = '\t'
          )
          
          func main() {
          	//1.网络监听
          	listener, err := net.Listen(serverNetwork, serverAddress)
          	if err != nil {
          		log.Fatalf("listener err:%s", err)
          	}
          	defer listener.Close()
          	log.Printf("get listener for the server [address:%s]", listener.Addr())
          	for true {
          		//2.等待客户端三次握手,建立连接
          		conn, err := listener.Accept()
          		if err != nil {
          			log.Fatalf("Accept err:%s", err)
          		}
          		log.Printf("established a connection with a client application [remote address:%s]", conn.RemoteAddr())
          		//3.接收客户端一个连接请求
          		go handleConn(conn)
          	}
          }
          
          /**
          处理每次请求
          */
          func handleConn(conn net.Conn) {
          	//1.退出时释放连接
          	defer conn.Close()
          	for true {
          		//2.设置读超时
          		conn.SetReadDeadline(time.Now().Add(time.Second * 10))
          		req, err := read(conn)
          		if err != nil {
          			if err == io.EOF {
          				log.Printf("conn is closed by another side:%s", err)
          				return
          			} else {
          				log.Printf("conn read err:%s", err)
          			}
          			break
          		}
          		log.Printf("received req :%s\n", req)
          	}
          
          }
          
          /**
          一次有边界的消息读取 + 字节缓冲区方式
          */
          func read(conn net.Conn) (string, error) {
          	//1.按字节读取
          	readBytes := make([]byte, 1)
          	//2. 设置字节缓冲区
          	var buffer bytes.Buffer
          	for true {
          		_, err := conn.Read(readBytes)
          		if err != nil {
          			return "", err
          		}
          		//3. 判断消息边界
          		if readBytes[0] == DELIMITER {
          			break
          		}
          		buffer.WriteByte(readBytes[0])
          	}
          	return buffer.String(), nil
          }
          
          /**
          千万不可用这个版本的read函数
          带缓冲器的读取器,使得存在 读取的数据 比你想要数据多一点
          每次的客户端请求进来都会新创建 读取器,意味着 上一次多读出来的数据会丢弃
          造成数据不完整,本应该留给后面一个读取器的数据,却被提前读到了前面一个读取器的缓冲区。
          
          */
          //func read(conn net.Conn) (string, error) {
          //	reader := bufio.NewReader(conn)
          //	reader.re
          //	readBytes, err := reader.ReadBytes(DELIMITER)
          //	if err != nil {
          //		return "", err
          //	}
          //
          //	return string(readBytes[:len(readBytes)-1]), nil
          //}
          
          
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小哥(xpc)

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

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

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

打赏作者

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

抵扣说明:

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

余额充值