【Java转Go】快速上手学习笔记(六)之网络编程篇一

目录

  • TCP
    • 一个简单案例
      • [server.go 服务端](#server.go 服务端)
      • [client.go 客户端](#client.go 客户端)
  • HTTP
      • [server.go 服务端](#server.go 服务端)
      • [client.go 客户端](#client.go 客户端)
  • RPC
  • WebSocket
      • [server.go 服务端](#server.go 服务端)
      • [client.go 客户端](#client.go 客户端)
  • 完整代码
    • [server.go 服务端](#server.go 服务端)
    • [client.go 客户端](#client.go 客户端)

go往期文章笔记:

【Java转Go】快速上手学习笔记(一)之环境安装篇

【Java转Go】快速上手学习笔记(二)之基础篇一

【Java转Go】快速上手学习笔记(三)之基础篇二

【Java转Go】快速上手学习笔记(四)之基础篇三

【Java转Go】快速上手学习笔记(五)之Gorm篇

这篇记的是网络编程相关的笔记。

TCP

开启服务端,监听连接的请求。示意图:

服务端:启动后,监听连接过来的客户端,每连接过来一个客户端,开启一个协程去和客户端进行交互(一个协程代表一个客户端)

客户端:根据服务端的IP和端口号去访问服务端,连接成功后可以向服务端发送消息。

连接的时候通过IP和端口号去连接,但是和客户端进行交流的是协程。

一个简单案例

创建两个文件夹,一个是server、一个是client,然后两个文件夹里面分别创建 server.go、client.go 文件,如下图:

server.go 服务端

go 复制代码
package main

import (
	"fmt"
	"io"
	"net"
)

// tcp处理客户端发送过来的信息
func tcpHandler(conn net.Conn) {
	defer conn.Close()
	for {
		var buf []byte = make([]byte, 1024)
		// 等待客户端通过conn发送信息,如果客户端没有wrtie[发送],那么协程就阻塞在这里
		n, err := conn.Read(buf)
		if err == io.EOF {
			fmt.Println(conn.RemoteAddr().String() + " 退出连接")
			break
		}
		// 客户端发送的内容显示到服务器的终端
		fmt.Print(string(buf[:n]))
	}
}

func main() {
	TCP服务端()
}

func TCP服务端() {
	fmt.Println("服务器开始监听")
	listen, err := net.Listen("tcp", "0.0.0.0:8888")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer listen.Close()
	for { // 循环等待客户端来连接
		conn, err := listen.Accept()
		if err != nil {
			fmt.Println(err)
		} else {
			fmt.Printf("客户端 %v 连接成功\n", conn.RemoteAddr().String())
		}
		// 这里开启协程
		go tcpHandler(conn)
	}
}

client.go 客户端

go 复制代码
package main

import (
	"fmt"
	"net"
)

func main() {
	TCP客户端()
}

func TCP客户端() {
	conn, err := net.Dial("tcp", "127.0.0.1:8888")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer conn.Close()
	fmt.Println(conn.RemoteAddr().String(), "连接成功")
	var s string
	for { // 循环输入,给服务端发送消息
		// 从终端读取用户输入,并发送给服务器
		fmt.Scanln(&s)
		if s == "exit" {
			fmt.Println(conn.RemoteAddr().String(), "退出连接")
			break
		}
		conn.Write([]byte(s + "\r\n")) // 发送给服务端
	}
}

写好之后,我们先启动服务端,然后再启动客户端。在客户端里面输入消息发送给服务端,服务端接收后要将消息显示出来。


客户端输入 exit 时,退出程序,关闭了连接,服务端也显示这个客户端已经退出了连接。

HTTP

server.go 服务端

go 复制代码
// http处理请求
func httpHandler(res http.ResponseWriter, req *http.Request) {
	switch req.Method {
	case "GET":
		fmt.Println("这里是get请求")
		res.Write([]byte("这里是get请求"))
	case "POST":
		defer req.Body.Close()
		// 1、 请求类型是aplication/x-www-form-urlencode时解析form数据
		//req.ParseForm()
		//fmt.Println(req.PostForm) //打印form数数据
		//fmt.Println(req.PostForm.Get("username"), req.PostForm.Get("password"))

		// 2、请求类型是application/json时从req.Body读取数据
		b, err := io.ReadAll(req.Body)
		if err != nil {
			fmt.Println("获取请求数据错误", err)
			return
		}
		fmt.Println(string(b))
		result := `{"code":0,"message":"ok","data":{}}` // 请求成功,返回数据
		res.Write([]byte(result))
	}
}

func main() {
	HTTP服务端()
}

func HTTP服务端() {
	http.HandleFunc("/index", httpHandler) // 回调函数
	fmt.Println("http://localhost:8080")
	http.ListenAndServe(":8080", nil) // 绑定服务
}

client.go 客户端

go 复制代码
func main() {
	HTTP客户端()
}

func HTTP客户端() {
	data := `{"username":"符华","password":"123456"}`
	//resp, err := http.Get("http://localhost:8080/index")
	resp, err := http.Post("http://localhost:8080/index", "application/json", strings.NewReader(data))
	//resp, err := http.PostForm("http://localhost:8080/index", url.Values{"username": {"符华"}, "password": {"123456"}})
	if err != nil {
		fmt.Println("请求错误", err)
		return
	}
	defer resp.Body.Close()

	b, err := io.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("获取返回数据错误", err)
		return
	}
	fmt.Println(string(b))
}

RPC

一个很简单的示例

server.go 服务端

go 复制代码
import (
	"net"
	"net/http"
	"net/rpc"
)

type Server struct{}
type Req struct {
	Num1 int
	Num2 int
}
type Res struct {
	Num int
}

func (s Server) Add(req Req, res *Res) error {
	res.Num = req.Num1 + req.Num2
	return nil
}

func RPC服务端() {
	// 注册rpc服务
	rpc.Register(new(Server))
	rpc.HandleHTTP()
	listen, err := net.Listen("tcp", ":8080")
	if err != nil {
		fmt.Println(err)
		return
	}
	http.Serve(listen, nil)
}

func main() {
	RPC服务端()
}

client.go 客户端

go 复制代码
import (
	"fmt"
	"net"
	"net/rpc"
)

type Req struct {
	Num1 int
	Num2 int
}
type Res struct {
	Num int
}

func RPC客户端() {
	req := Req{1, 2}
	client, err := rpc.DialHTTP("tcp", ":8080")
	if err != nil {
		fmt.Println(err)
		return
	}
	var res Res
	client.Call("Server.Add", req, &res)
	fmt.Println(res)
}

func main() {
	RPC客户端()
}

WebSocket

websocket是socket连接和http协议的结合体,可以实现网页和服务端的长连接。

要使用websocket我们要先去下载依赖

go 复制代码
go get github.com/gorilla/websocket

server.go 服务端

go 复制代码
// websocke 连接的升级器。升级器是一个http.HandlerFunc,它将HTTP连接升级为WebSocket连接
var UP = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
}
var conns []*websocket.Conn // 客户端连接切片,存储所有的客户端连接

// websocket处理请求
func websocketHandler(res http.ResponseWriter, req *http.Request) {
	conn, err := UP.Upgrade(res, req, nil) // 服务升级
	if err != nil {
		fmt.Println(err)
		return
	}
	defer conn.Close()
	conns = append(conns, conn)
	for {
		// 消息类型,消息,错误
		t, p, err := conn.ReadMessage()
		if err != nil {
			break
		}
		for index := range conns {
			conns[index].WriteMessage(websocket.TextMessage, []byte(fmt.Sprintf("你说的是:%s吗?", string(p))))
		}
		fmt.Println(t, string(p))
	}
	fmt.Println("服务关闭")
}

func websocket服务端() {
	http.HandleFunc("/", websocketHandler)
	http.ListenAndServe(":8080", nil)
}

client.go 客户端

go 复制代码
// websocket 发送消息
func send(conn *websocket.Conn) {
	for {
		reader := bufio.NewReader(os.Stdin)
		l, _, _ := reader.ReadLine()
		conn.WriteMessage(websocket.TextMessage, l)
	}
}

func websocket客户端() {
	dl := websocket.Dialer{}
	conn, _, err := dl.Dial("ws://127.0.0.1:8080", nil)
	if err != nil {
		fmt.Println(err)
		return
	}
	go send(conn)
	for {
		t, p, err := conn.ReadMessage()
		if err != nil {
			break
		}
		fmt.Println(t, string(p))
	}
}

完整代码

server.go 服务端

go 复制代码
package main

import (
	"fmt"
	"github.com/gorilla/websocket"
	"io"
	"net"
	"net/http"
	"net/rpc"
)

// tcp处理客户端发送过来的信息
func tcpHandler(conn net.Conn) {
	defer conn.Close()
	for {
		var buf []byte = make([]byte, 1024)
		// 等待客户端通过conn发送信息,如果客户端没有wrtie[发送],那么协程就阻塞在这里
		n, err := conn.Read(buf)
		if err == io.EOF {
			fmt.Println(conn.RemoteAddr().String() + " 退出连接")
			break
		}
		// 客户端发送的内容显示到服务器的终端
		fmt.Print(string(buf[:n]))
	}
}

// http处理请求
func httpHandler(res http.ResponseWriter, req *http.Request) {
	switch req.Method {
	case "GET":
		fmt.Println("这里是get请求")
		res.Write([]byte("这里是get请求"))
	case "POST":
		defer req.Body.Close()
		// 1、 请求类型是aplication/x-www-form-urlencode时解析form数据
		//req.ParseForm()
		//fmt.Println(req.PostForm) //打印form数数据
		//fmt.Println(req.PostForm.Get("username"), req.PostForm.Get("password"))

		// 2、请求类型是application/json时从req.Body读取数据
		b, err := io.ReadAll(req.Body)
		if err != nil {
			fmt.Println("获取请求数据错误", err)
			return
		}
		fmt.Println(string(b))
		result := `{"code":0,"message":"ok","data":{}}` // 请求成功,返回数据
		res.Write([]byte(result))
	}
}

// RPC
type Server struct{}
type Req struct {
	Num1 int
	Num2 int
}
type Res struct {
	Num int
}

func (s Server) Add(req Req, res *Res) error {
	res.Num = req.Num1 + req.Num2
	return nil
}

// websocke 连接的升级器。升级器是一个http.HandlerFunc,它将HTTP连接升级为WebSocket连接
var UP = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
}
var conns []*websocket.Conn // 客户端连接切片,存储所有的客户端连接

// websocket处理请求
func websocketHandler(res http.ResponseWriter, req *http.Request) {
	conn, err := UP.Upgrade(res, req, nil) // 服务升级
	if err != nil {
		fmt.Println(err)
		return
	}
	defer conn.Close()
	conns = append(conns, conn)
	for {
		// 消息类型,消息,错误
		t, p, err := conn.ReadMessage()
		if err != nil {
			break
		}
		for index := range conns {
			conns[index].WriteMessage(websocket.TextMessage, []byte(fmt.Sprintf("你说的是:%s吗?", string(p))))
		}
		fmt.Println(t, string(p))
	}
	fmt.Println("服务关闭")
}

func main() {
	//TCP服务端()
	//HTTP服务端()
	//RPC服务端()
	websocket服务端()
}

func TCP服务端() {
	fmt.Println("服务器开始监听")
	listen, err := net.Listen("tcp", "0.0.0.0:8080")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer listen.Close()
	for { // 循环等待客户端来连接
		conn, err := listen.Accept()
		if err != nil {
			fmt.Println(err)
		} else {
			fmt.Printf("客户端 %v 连接成功\n", conn.RemoteAddr().String())
		}
		// 这里开启协程
		go tcpHandler(conn)
	}
}

func HTTP服务端() {
	http.HandleFunc("/index", httpHandler) // 回调函数
	fmt.Println("http://localhost:8080")
	http.ListenAndServe(":8080", nil) // 绑定服务
}

func RPC服务端() {
	// 注册rpc服务
	rpc.Register(new(Server))
	rpc.HandleHTTP()
	listen, err := net.Listen("tcp", ":8080")
	if err != nil {
		fmt.Println(err)
		return
	}
	http.Serve(listen, nil)
}

func websocket服务端() {
	http.HandleFunc("/", websocketHandler)
	http.ListenAndServe(":8080", nil)
}

client.go 客户端

go 复制代码
package main

import (
	"bufio"
	"fmt"
	"github.com/gorilla/websocket"
	"io"
	"net"
	"net/http"
	"net/rpc"
	"os"
	"strings"
)

func main() {
	//TCP客户端()
	//HTTP客户端()
	//RPC客户端()
	websocket客户端()
}

func TCP客户端() {
	conn, err := net.Dial("tcp", "127.0.0.1:8080")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer conn.Close()
	fmt.Println(conn.RemoteAddr().String(), "连接成功")
	var s string
	for { // 循环输入,给服务端发送消息
		// 从终端读取用户输入,并发送给服务器
		fmt.Scanln(&s)
		if s == "exit" {
			fmt.Println(conn.RemoteAddr().String(), "退出连接")
			break
		}
		conn.Write([]byte(s + "\r\n")) // 发送给服务端
	}
}

func HTTP客户端() {
	data := `{"username":"符华","password":"123456"}`
	//resp, err := http.Get("http://localhost:8080/index")
	resp, err := http.Post("http://localhost:8080/index", "application/json", strings.NewReader(data))
	//resp, err := http.PostForm("http://localhost:8080/index", url.Values{"username": {"符华"}, "password": {"123456"}})
	if err != nil {
		fmt.Println("请求错误", err)
		return
	}
	defer resp.Body.Close()

	b, err := io.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("获取返回数据错误", err)
		return
	}
	fmt.Println(string(b))
}

// RPC
type Req struct {
	Num1 int
	Num2 int
}
type Res struct {
	Num int
}

func RPC客户端() {
	req := Req{1, 2}
	client, err := rpc.DialHTTP("tcp", ":8080")
	if err != nil {
		fmt.Println(err)
		return
	}
	var res Res
	client.Call("Server.Add", req, &res)
	fmt.Println(res)
}

// websocket 发送消息
func send(conn *websocket.Conn) {
	for {
		reader := bufio.NewReader(os.Stdin)
		l, _, _ := reader.ReadLine()
		conn.WriteMessage(websocket.TextMessage, l)
	}
}

func websocket客户端() {
	dl := websocket.Dialer{}
	conn, _, err := dl.Dial("ws://127.0.0.1:8080", nil)
	if err != nil {
		fmt.Println(err)
		return
	}
	go send(conn)
	for {
		t, p, err := conn.ReadMessage()
		if err != nil {
			break
		}
		fmt.Println(t, string(p))
	}
}

ok,以上就是本篇笔记的全部内容了,就是一些简单的使用示例,关于理论概念的东西我没有记,因为太多了,不知道要怎么整理才能说明白说清楚,反正就是这么用的。

相关推荐
古城小栈1 天前
Go 底层代码的完整分类
开发语言·后端·golang
耳冉鹅1 天前
Go无锁共享内存环形缓冲区设计
开发语言·golang
程序员爱钓鱼1 天前
Go PDF处理利器: github.com/pdfcpu/pdfcpu 深度指南
后端·面试·go
江湖十年1 天前
使用 testing/synctest 测试并发代码
后端·面试·go
fy121632 天前
GO 快速升级Go版本
开发语言·redis·golang
童话ing2 天前
【Golang】Golang Map数据结构底层原理
数据结构·golang·哈希算法
比特森林探险记2 天前
Go 语言依赖注入和java 区别
go
GDAL2 天前
go.mod 文件讲解
golang·go.mod
不会聊天真君6472 天前
基础语法·上(golang笔记第一期)
go
Java面试题总结2 天前
Go图像处理基础: image包深度指南
图像处理·算法·golang