Golang入门学习之网络编程--筑基八层

·  阅读 96
Golang入门学习之网络编程--筑基八层

写在前面

在前面的文章当中,我们学习了go当中的通道(channel)与协程(go-routine)及其应用。接下来,我们将学习go关于网络编程方面的内容。

Golang网络编程初识

在正式的跟大家讲解网络编程之前,需要提前跟大家说明一下:网络编程是一个很庞大的领域,本文当中只是通过一些简单的demo带大家初步了解golang在网络编程方面的应用。

为了大家能够更好地理解本文,大家需要先了解互联网协议的相关知识点。这包括OSI七层模型,了解各层的作用、协议等。如果大家学习过其他的高级语言,例如Java、Python等,了解socket编程的相关知识点,那这再好不过。

Golang socket编程

socket是什么?

socket是一种操作系统提供的进程间通信机制,中文翻译为“套接字”。它用于描述IP地址和端口,是一个通信链的句柄。

socket最初被翻译为把socket译为“介质(字)”。不久,ARPANET的socket就被翻译为“套接字”,其理由是:

由于每个主机系统都有各自命名进程的方法,而且常常是不兼容的,因此,要在全网范围内硬把进程名字统一起来是不现实的。所以,每个计算机网络中都要引入一种起介质作用的、全网一致的标准名字空间。这种标准名字,在ARPA网中称作套接字,而在很多其他计算机网中称作信口。更确切地说,进程之间的连接是通过套接字或信口构成的。

在操作系统当中,通常会为应用程序提供一组API,称之为套接字接口。应用程序可以通过套接字接口,向网络发出请求或者应答网络请求,进行数据交换。

一个套接字对(socket pairs)由本地的IP地址和端口、远程的IP地址和端口以及建立连接所使用的协议(protocol)组成。

对于socket的理解

socket位于应用层与TCP/IP协议族通信的中间,相当于设计模式当中的门面。对于程序员来说,不需要关系通信协议的具体实现,只需要调用socket提供的相关API,就可以进行网络数据交换。

Golang的TCP client-server Demo

服务端程序:

package main

import (
	"fmt"
	"go_code/web/tcp/constants"
	"net"
	"time"
)

func main() {

	listen, err := net.Listen(constants.Protocol, constants.Addr)

	if err != nil {
		println("监听端口出错", err)
		return

	} else {
		fmt.Println("服务器启动完成 " + time.Now().Format("2006-01-02 15:04:05"))
	}

	for {

		accept, err := listen.Accept()
		if err != nil {
			println("出现错误:\n", err.Error())
			return

		}

		go doServerStuff(accept)

	}

}

func doServerStuff(conn net.Conn) {

	defer func() {
		println("关闭连接")
		conn.Close()
	}()

	for {
		buf := make([]byte, 256)

		read, err := conn.Read(buf)

		if err != nil {
			if "EOF" == err.Error() {
				println("数据读取结束")
				return
			}
			println("出现错误:", err.Error())
			return

		}

		println("接收到数据:")
		println(string(buf[:read]))
		_, err = conn.Write([]byte(" hello client " + conn.RemoteAddr().String()))

		if err != nil {
			println("出现错误\n", err.Error())
		}

	}

}

在服务端程序当中,服务启动后,使用for无限循环接收客户端的请求并启动协程处理来自客户端的请求。

客户端程序:

package main

import (
	"fmt"
	"go_code/web/tcp/constants"
	"net"
	"time"
)

func main() {

	// 建立连接

	conn, err := net.Dial(constants.Protocol, constants.Addr)

	defer conn.Close()

	if err != nil {
		println("建立连接失败", err.Error())
		return

	} else {
		fmt.Println("建立连接成功")
	}
	conn.Write([]byte("hello server " + time.Now().Format("2006-01-02 15:04:05")))

	buf := make([]byte, 1024)
	read, err := conn.Read(buf)

	println("收到服务器发送来的消息")

	if err != nil {
		println("读取数据失败 ", err.Error())
		return
	}

	fmt.Println(string(buf[:read]))

}

客户端启动后,与服务器建立连接,并向服务器发送数据。

服务器程序输出:

服务器启动完成 2022-01-16 18:37:53
接收到数据:
hello server 2022-01-16 18:38:01
数据读取结束
关闭连接

客户端程序输出:

建立连接成功
收到服务器发送来的消息
 hello client 127.0.0.1:3471

进程完成,并显示退出代码 0

以上就是Go 关于tcp编程的一个简单的demo,其中主要应用到了net包和协程的相关知识点。

http 服务器demo

接下来,我们通过一个小demo来学习Go当中简单的http服务编程的相关知识点。

constants.go

package constants

const (
	ADDR         = "localhost:9527"
	CONTEXT_PATH = "/"
)

http_server.go

package main

import (
	"go_code/web/http/constants"
	"net/http"
	"strings"
)

var handlerMap = map[string]http.HandlerFunc{}

func main() {

	handlerMap["/sayHello"] = SayHelloHandler
	handlerMap["/goodbye"] = SayGoodbyeHandler

	http.HandleFunc(constants.CONTEXT_PATH, BaseHandler)

	err := http.ListenAndServe(constants.ADDR, nil)

	if err != nil {
		println("启动http服务器错误\n", err.Error())
	}

}

func BaseHandler(w http.ResponseWriter, r *http.Request) {

	uri := strings.Split(r.RequestURI, "?")[0]

	println("请求URI ", uri)
	//println(i)

	handlerFunc, ok := handlerMap[uri]
	if ok {
		handlerFunc(w, r)
	} else {

		w.WriteHeader(http.StatusNotFound)
		_, _ = w.Write([]byte("请求资源不存在"))

	}
}

func SayHelloHandler(w http.ResponseWriter, r *http.Request) {

	// 获取get请求参数
	name := r.URL.Query().Get("name")

	if name != "" {
		_, _ = w.Write([]byte("hello ! " + name))
	} else {
		w.WriteHeader(http.StatusBadRequest)
		_, _ = w.Write([]byte("缺少参数name"))
	}
}

func SayGoodbyeHandler(w http.ResponseWriter, r *http.Request) {

	name := r.FormValue("name")
	if name != "" {
		_, _ = w.Write([]byte("goodbye ! " + name))
	} else {
		w.WriteHeader(http.StatusBadRequest)
		_, _ = w.Write([]byte("缺少参数name"))
	}
}

在这个例子当中,http.ListenAndServe函数主要用来监听并启动http服务,如果启动出现异常,则会返回相应的error。http.HandleFunc函数用于注册对应请求路径的处理函数,在这个例子当中,我们对/路径注册了对应的处理函数BaseHandler,它实现于http包中的Handler接口。在BaseHandler接口当中我们再对请求进一步的转发到具体的处理器函数。

而具体的处理函数也很简单,分别是一个sayHello和sayGoodbye的模拟业务处理的函数。当程序启动后,使用curl进行测试

程序输出:

curl http://localhost:9527/sayHello?name=韩立
hello ! 韩立
curl http://localhost:9527/sayHello
缺少参数name
curl http://localhost:9527/sayHell
请求资源不存在
curl http://localhost:9527/goodbye?name=陈师姐
goodbye ! 陈师姐

写在最后

在这篇文章当中,我们主要通过两个例子初步地认识了go语言网络编程的相关知识点。本文当中涉及到的例子可以点击此处下载。如果我的学习笔记能够给你带来帮助,还请多多点赞鼓励。文章如有错漏之处还请各位小伙伴帮忙斧正。

分类:
后端
标签:
分类:
后端
标签:
收藏成功!
已添加到「」, 点击更改