zoukankan      html  css  js  c++  java
  • [go]socket编程

    [net]tcp和udp&socket

    socket特性

    • 总是成对出现

    • 是全双工的(同时支持收发)(两个channel绑在一起)

    应用程序
    - cs模式(客户端开发)
    - bs模式(web开发)

    net包api基础

    都是客户端主动发数据(client request)

    一共有3个soket。用于通信的有2个。另一个用于监听ip端口

    // 服务端
    
    import (
    	"net"
    )
    
    listener, err := net.Listen("tcp", "127.0.0.1:8000") //生成监听socket
    defer listener.Close()
    
    conn, err := listener.Accept() //[**阻塞] 生成读写socket
    defer conn.Close()
    
    buf := make([]byte, 4096)
    n, err := conn.Read(buf) //[**阻塞]
                             //读客户端数据(client request)
    conn.Write(buf[:n])      //写数据给客户端
    
    //客户端
    
    conn, err := net.Dial("tcp", "127.0.0.1:8000")
    defer conn.Close()
    
    conn.Write([]byte("Are you Ready?")) //写数据
    
    buf := make([]byte, 4096) //读数据
    n, err := conn.Read(buf)
    fmt.Println("服务器回发:", string(buf[:n]))
    
    

    实现conn复用: 循环读写

    //server
    
    func main() {
    	listener, _ := net.Listen("tcp", ":3000")
    	defer listener.Close()
    	conn, _ := listener.Accept()
    	defer conn.Close()
    	buf := make([]byte, 1024)
    	for {
    		n, _ := conn.Read(buf)
    		if n==0{ //客户端关闭时候server退出
    			return
    		}
    		fmt.Println(string(buf[:n]))
    		conn.Write([]byte("i am server"))
    		time.Sleep(time.Second / 3)
    	}
    }
    
    // client
    
    func main() {
    	conn, _ := net.Dial("tcp", ":3000")
    	defer conn.Close()
    	buf := make([]byte, 1024)
    	for {
    		conn.Write([]byte("hi server"))
    
    		n, _ := conn.Read(buf)
    		fmt.Println(string(buf[:n]))
    		time.Sleep(time.Second/3)
    	}
    }
    

    server支持并发

    // server
    
    func main() {
    	listener, _ := net.Listen("tcp", ":3000")
    	defer listener.Close()
    	for {
    		conn, _ := listener.Accept()
    		go func(conn net.Conn) {
    			defer conn.Close()
    			buf := make([]byte, 1024)
    			for {
    				n, _ := conn.Read(buf) //已关闭的chan中往出读数据会一直读出零值
    				if n == 0 {
    					return
    				}
    				fmt.Println(string(buf[:n]))
    				conn.Write([]byte("i am server"))
    				time.Sleep(time.Second / 3)
    			}
    		}(conn)
    	}
    
    	time.Sleep(time.Second * 1000)
    }
    
    
    //client
    
    func main() {
    	conn, _ := net.Dial("tcp", ":3000")
    	defer conn.Close()
    	buf := make([]byte, 1024)
    	for {
    		conn.Write([]byte("hi server"))
    
    		n, _ := conn.Read(buf)
    		fmt.Println(string(buf[:n]))
    		time.Sleep(time.Second/3)
    	}
    }
    

    server并发-处理退出等.问题

    // 并发版的server: 复用lisntner.Accept
    
    package main
    
    import (
    	"net"
    	"fmt"
    	"strings"
    )
    
    func HandlerConnect(conn net.Conn) {
    
    	defer conn.Close()
    
    	// 获取连接的客户端 Addr
    	addr := conn.RemoteAddr()
    	fmt.Println(addr, "客户端成功连接!")
    
    	// 循环读取客户端发送数据
    	buf := make([]byte, 4096)
    	for {
    		n, err := conn.Read(buf)
    		//fmt.Println(buf[:n])
    		if "exit
    " == string(buf[:n]) || "exit
    " == string(buf[:n]) {
    			fmt.Println("服务器接收的客户端退出请求,服务器关闭")
    			return
    		}
    		if n == 0 {
    			fmt.Println("服务器检测到客户端已关闭,断开连接!!!")
    			return
    		}
    		if err != nil {
    			fmt.Println("conn.Read err:", err)
    			return
    		}
    		fmt.Println("服务器读到数据:", string(buf[:n]))	// 使用数据
    
    		// 小写转大写,回发给客户端
    		conn.Write([]byte(strings.ToUpper(string(buf[:n]))))
    	}
    }
    
    func main()  {
    	// 创建监听套接字
    	//listener, err := net.Listen("tcp", "127.0.0.1:8001")
    	listener, err := net.Listen("tcp", "192.168.15.78:8001")
    	if err != nil {
    		fmt.Println("net.Listen err:", err)
    		return
    	}
    	defer listener.Close()
    
    	// 监听客户端连接请求
    	for {
    		fmt.Println("服务器等待客户端连接...")
    		conn, err := listener.Accept()
    		if err != nil {
    			fmt.Println("listener.Accept err:", err)
    			return
    		}
    		// 具体完成服务器和客户端的数据通信
    		go HandlerConnect(conn)
    	}
    }
    
    
    //并发版的客户端
    
    package main
    
    import (
    	"net"
    	"fmt"
    	"os"
    )
    
    func main()  {
    	// 主动发起连接请求
    	conn, err := net.Dial("tcp", "192.168.15.78:8001")
    	if err != nil {
    		fmt.Println("net.Dial err:", err)
    		return
    	}
    	defer conn.Close()
    	// 获取用户键盘输入( stdin ),将输入数据发送给服务器
    	go func() {
    		str := make([]byte, 4096)
    		for {
    			n, err := os.Stdin.Read(str)
    			if err != nil {
    				fmt.Println("os.Stdin.Read err:", err)
    				continue
    			}
    			//写给服务器, 读多少,写多少!
    			conn.Write(str[:n])
    		}
    	}()
    
    	// 回显服务器回发的大写数据
    	buf := make([]byte, 4096)
    	for {
    		n, err := conn.Read(buf)
    		if n == 0 {
    			fmt.Println("检查到服务器关闭,客户端也关闭")
    			return
    		}
    		if err != nil {
    			fmt.Println("conn.Read err:", err)
    			return
    		}
    		fmt.Println("客户端读到服务器回发:", string(buf[:n]))
    	}
    }
    
    
  • 相关阅读:
    C++11 override和final
    C++11 类型推导auto
    C++11 强枚举类型
    C++11 explicit的使用
    《数据结构与算法之美》——冒泡排序、插入排序、选择排序
    《数据结构与算法之美》- 栈
    Spring Boot系列——AOP配自定义注解的最佳实践
    Spring Boot系列——死信队列
    Spring Boot系列——7步集成RabbitMQ
    让我头疼一下午的Excel合并单元格
  • 原文地址:https://www.cnblogs.com/iiiiiher/p/11962062.html
Copyright © 2011-2022 走看看