zoukankan      html  css  js  c++  java
  • Golang Sockek编程

    网络基本概念

    • 网络编程的目的:直接或间接地通过网络协议与其他计算机进行通讯
    • 网络编程中两个主要问题:
    • 如何准确定位网络上一台或多台主机(通过 IP 地址)
    • 找到主机后如何进行数据传输(有 OSI 模型和 TCP/IP 模型)
    • OSI 模型将网络分为 7 层,过于理想化,未能广泛推广
    • TCP/IP 是事实上的国际标准
    OSI TCP/IP TCP/IP 对应的协议
    应用层 应用层 HTTP、FTP、DNS
    表示层
    会话层
    传输层 传输层 TCP、UDP
    网络层 网络层 IP、ARP、ICMP
    数据链路层 物理数据层 Link
    物理层
    • IP 分类:最开始是 32 位整数,后来用圆点隔开,分成 4 段,8 位一段

      • A 类:保留给政府结构,1.0.0.1 ~ 126.255.255.254
      • B 类:分配给中型企业,1.0.0.1 ~ 126.255.255.254
      • C 类:分配给任何需要的个人,192.0.0.1 ~ 223.255.255.254
      • D 类:用于组播,224.0.0.1 ~ 239.255.255.254
      • E 类:用于实验,240.0.0.1 ~ 255.255.255.254
      • 回环地址:127.0.0.1,指本地机,一般用于测试使用
    • 端口号:0~65535

    什么是 socket

    • Socket 又称套接字,应用程序通常通过“套接字”向网络发出请求或者应答网络请求
    • 常用的 Socket 类型有两种:流式 Socket 和数据报式 Socket,流式是一种面向连接的 Socket,针对于面向连接的 TCP 服务应用,数据报式 Socket 是一种无连接的 Socket,针对于无连接的 UDP 服务应用
    • TCP:比较靠谱,面向连接,比较慢
    • UDP:不是太靠谱,比较快

    TCP 编程

    • 实现服务端与客户端通信,保持连接,服务器接收到 exit 时再断开连接

    服务端

    package main
    
    import (
    	"fmt"
    	"io"
    	"net"
    	"strings"
    )
    
    // 处理客户端数据
    func clientHandle(conn net.Conn) {
    	// 关闭客户端连接
    	defer conn.Close()
    	// 获取客户端地址
    	clientAddr := conn.RemoteAddr()
    	fmt.Printf("%v 已连接
    ", clientAddr)
    
    	// 创建读去数据的缓冲区
    	buf := make([]byte, 1024)
    	for {
    		// 读取数据
    		// n是读取到的长度
    		n, err := conn.Read(buf)
    		if err == io.EOF { // 读取完毕
    			break
    		}
    		if err != nil { // 读取失败
    			fmt.Println("读取客户端数据失败, err: ", err)
    			return
    		}
    
    		// 取出接收到的数据
    		readResult := string(buf[:n])
    		// 判断是否为退出指令
    		if readResult == "exit" {
    			fmt.Printf("%d退出连接", clientAddr)
    			return
    		}
    		fmt.Printf("接收到来自[%v]数据: %s", clientAddr, readResult)
    		// 回复客户端
    		_, err = conn.Write([]byte(strings.ToUpper(readResult)))
    		if err != nil {
    			fmt.Printf("给 %v 发送数据失败: %v", clientAddr, err)
    			return
    		}
    	}
    }
    
    func main() {
    	// 1. 创建服务端监听
    	listener, err := net.Listen("tcp", "127.0.0.1:8080")
    	if err != nil {
    		fmt.Println("启动服务端失败, err: ", err)
    		return
    	}
    	// 关闭服务端资源
    	defer listener.Close()
    
    	fmt.Println("服务端启动成功")
    
    	// 循环监听服务端
    	for {
    		// 堵塞监听
    		conn, err := listener.Accept()
    		if err != nil {
    			fmt.Println("堵塞监听失败, err: ", err)
    			continue
    		}
    		// 启动协程去处理客户端请求
    		go clientHandle(conn)
    	}
    }
    

    客户端

    package main
    
    import (
    	"fmt"
    	"net"
    )
    
    func main() {
    	// 创建连接
    	conn, err := net.Dial("tcp", "127.0.0.1:8080")
    	if err != nil {
    		fmt.Println("创建连接失败, err: ", err)
    		return
    	}
    	defer conn.Close()
    	// 创建缓冲区
    	buf := make([]byte, 1024)
    
    	for {
    		fmt.Printf("请输入要发送的内容: ")
    		_, err = fmt.Scan(&buf)
    		if err != nil {
    			fmt.Println("接收输入有误, err: ", err)
    			continue
    		}
    		fmt.Printf("发送内容[%s]到服务端
    ", string(buf))
    
    		// 发送数据
    		_, err = conn.Write(buf)
    		if err != nil {
    			fmt.Println("发送数据失败")
    			continue
    		}
    
    		// 读取数据
    		rn, err := conn.Read(buf)
    		if err != nil {
    			fmt.Println("读取数据失败")
    			continue
    		}
    		fmt.Printf("接收到数据: %s
    ", string(buf[:rn]))
    	}
    }
    

    UDP 编程

    • 编写客户端发送信息给服务,服务端返回信息,返回完切断

    服务端

    package main
    
    import (
    	"fmt"
    	"net"
    )
    
    func main() {
    	// 创建udp监听
    	conn, err := net.ListenUDP("udp", &net.UDPAddr{
    		IP:   net.IPv4(127, 0, 0, 1),
    		Port: 8080,
    	})
    	if err != nil {
    		fmt.Println("创建监听失败, err: ", err)
    		return
    	}
    	defer conn.Close()
    
    	for {
    		// 创建缓冲区
    		buf := make([]byte, 1024)
    
    		// 接收UDP传输
    		n, addr, err := conn.ReadFromUDP(buf)
    		if err != nil {
    			fmt.Println(err)
    			continue
    		}
    		fmt.Printf("来自: %s 接收到数据: %s
    ", addr, string(buf[:n]))
    		// 返回信息
    		_, err = conn.WriteToUDP([]byte("666"), addr)
    		if err != nil {
    			fmt.Println("err")
    			continue
    		}
    	}
    }
    

    客户端

    package main
    
    import (
    	"fmt"
    	"net"
    	"time"
    )
    
    func main() {
    	// 连接服务端
    	conn, err := net.DialUDP("udp4", nil, &net.UDPAddr{
    		IP:   net.IPv4(127, 0, 0, 1),
    		Port: 8080,
    	})
    	if err != nil {
    		fmt.Println("连接udp服务失败")
    	}
    	defer conn.Close()
    
    	for {
    		// 发送数据到服务端
    		_, err = conn.Write([]byte("老铁"))
    		if err != nil {
    			fmt.Println("发送数据失败, err: ", err)
    			return
    		}
    
    		buf := make([]byte, 1024)
    		n, addr, err := conn.ReadFromUDP(buf)
    		if err != nil {
    			fmt.Println("接收服务端数据失败, err: ", err)
    			return
    		}
    		fmt.Printf("服务端: %v, 数据: %s
    ", addr, string(buf[:n]))
    		time.Sleep(time.Second)
    	}
    }
    
  • 相关阅读:
    23种设计模式之单例模式
    6大设计原则之里氏替换原则
    6大设计原则之依赖倒置原则
    6大设计原则之接口隔离原则
    6大设计原则之迪米特法则
    Java日志第14天 2020.7.19
    Java日志第15天 2020.7.20
    Java日志第13天 2020.7.18
    Python 语音识别字幕生成器
    python list,tuple,str有序问题
  • 原文地址:https://www.cnblogs.com/zhichaoma/p/12510021.html
Copyright © 2011-2022 走看看