[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\n" == string(buf[:n]) || "exit\r\n" == 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]))
	}
}

posted @ 2019-11-30 12:52  mmaotai  阅读(418)  评论(0编辑  收藏  举报