一 socket编程
1.1 服务器代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| package main
import ( "fmt" "log" "net" "strings" )
func dealConn(conn net.Conn) {
defer conn.Close() //此函数结束时,关闭连接套接字
//conn.RemoteAddr().String():连接客服端的网络地址 ipAddr := conn.RemoteAddr().String() fmt.Println(ipAddr, "连接成功")
buf := make([]byte, 1024) //缓冲区,用于接收客户端发送的数据
for { //阻塞等待用户发送的数据 n, err := conn.Read(buf) //n代码接收数据的长度 if err != nil { fmt.Println(err) return } //切片截取,只截取有效数据 result := buf[:n] fmt.Printf("接收到数据来自[%s]==>[%d]:%s\n", ipAddr, n, string(result)) if "exit" == string(result) { //如果对方发送"exit",退出此链接 fmt.Println(ipAddr, "退出连接") return }
//把接收到的数据转换为大写,再给客户端发送 conn.Write([]byte(strings.ToUpper(string(result)))) } }
func main() { //创建、监听socket listenner, err := net.Listen("tcp", "127.0.0.1:8000") if err != nil { log.Fatal(err) //log.Fatal()会产生panic }
defer listenner.Close()
for { conn, err := listenner.Accept() //阻塞等待客户端连接 if err != nil { log.Println(err) continue }
go dealConn(conn) } }
|
1.2 客服端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| package main
import ( "fmt" "log" "net" )
func main() { //客户端主动连接服务器 conn, err := net.Dial("tcp", "127.0.0.1:8000") if err != nil { log.Fatal(err) //log.Fatal()会产生panic return }
defer conn.Close() //关闭
buf := make([]byte, 1024) //缓冲区 for { fmt.Printf("请输入发送的内容:") fmt.Scan(&buf) fmt.Printf("发送的内容:%s\n", string(buf))
//发送数据 conn.Write(buf)
//阻塞等待服务器回复的数据 n, err := conn.Read(buf) //n代码接收数据的长度 if err != nil { fmt.Println(err) return }
//切片截取,只截取有效数据 result := buf[:n] fmt.Printf("接收到数据[%d]:%s\n", n, string(result)) } }
|
二 HTTP编程
2.1 HTTP报文浅析
2.1.1 请求报文格式
服务器测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| package main
import ( "fmt" "log" "net" )
func main() { //创建、监听socket listenner, err := net.Listen("tcp", "127.0.0.1:8000") if err != nil { log.Fatal(err) //log.Fatal()会产生panic }
defer listenner.Close()
conn, err := listenner.Accept() //阻塞等待客户端连接 if err != nil { log.Println(err) return }
defer conn.Close() //此函数结束时,关闭连接套接字
//conn.RemoteAddr().String():连接客服端的网络地址 ipAddr := conn.RemoteAddr().String() fmt.Println(ipAddr, "连接成功")
buf := make([]byte, 4096) //缓冲区,用于接收客户端发送的数据
//阻塞等待用户发送的数据 n, err := conn.Read(buf) //n代码接收数据的长度 if err != nil { fmt.Println(err) return }
//切片截取,只截取有效数据 result := buf[:n] fmt.Printf("接收到数据来自[%s]==>:\n%s\n", ipAddr, string(result)) }
|
浏览器输入url地址:
http://localhost:8000/
服务器端运行打印结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| C:/Users/qingteng/Desktop/aa/src/src.exe [C:/Users/qingteng/Desktop/aa/src] 127.0.0.1:34680 连接成功 接收到数据来自[127.0.0.1:34680]==>: GET / HTTP/1.1 Host: localhost:8000 Connection: keep-alive Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36 Sec-Fetch-User: ?1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3 Sec-Fetch-Site: none Sec-Fetch-Mode: navigate Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Cookie: Hm_lvt_b15e599ba57327dec9b15e0680fa81fc=1596812405,1598105048,1598707525
成功: 进程退出代码 0.
|
2.1.2 响应报文格式
服务器示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package main
import ( "fmt" "net/http" )
//服务端编写的业务逻辑处理程序 func myHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "hello world") }
func main() { http.HandleFunc("/go", myHandler)
//在指定的地址进行监听,开启一个HTTP http.ListenAndServe("127.0.0.1:8000", nil) }
|
2.2 HTTP编程
Go语言标准库内建提供了net/http包,涵盖了HTTP客户端和服务端的具体实现。使用net/http
包,我们可以很方便地编写HTTP客户端或服务端的程序。
2.2.1 http服务端
HTTP服务端示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| package main
import ( "fmt" "net/http" )
//服务端编写的业务逻辑处理程序 //hander函数: 具有func(w http.ResponseWriter, r *http.Requests)签名的函数 func myHandler(w http.ResponseWriter, r *http.Request) { fmt.Println(r.RemoteAddr, "连接成功") //r.RemoteAddr远程网络地址 fmt.Println("method = ", r.Method) //请求方法 fmt.Println("url = ", r.URL.Path) fmt.Println("header = ", r.Header) fmt.Println("body = ", r.Body)
w.Write([]byte("hello go")) //给客户端回复数据 }
func main() { http.HandleFunc("/go", myHandler)
//该方法用于在指定的 TCP 网络地址 addr 进行监听,然后调用服务端处理程序来处理传入的连接请求。 //该方法有两个参数:第一个参数 addr 即监听地址;第二个参数表示服务端处理程序,通常为空 //第二个参数为空意味着服务端调用 http.DefaultServeMux 进行处理 http.ListenAndServe("127.0.0.1:9000", nil) }
|
在浏览器里输入
http://localhost:9000/go
即可看到结果
2.2.2 客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| package main
import ( "fmt" "io" "log" "net/http" )
func main() {
//get方式请求一个资源 //resp, err := http.Get("http://www.baidu.com") //resp, err := http.Get("http://www.neihan8.com/article/index.html") resp, err := http.Get("http://127.0.0.1:8000/go") if err != nil { log.Println(err) return }
defer resp.Body.Close() //关闭
fmt.Println("header = ", resp.Header) fmt.Printf("resp status %s\nstatusCode %d\n", resp.Status, resp.StatusCode) fmt.Printf("body type = %T\n", resp.Body)
buf := make([]byte, 2048) //切片缓冲区 var tmp string
for { n, err := resp.Body.Read(buf) //读取body包内容 if err != nil && err != io.EOF { fmt.Println(err) return }
if n == 0 { fmt.Println("读取内容结束") break } tmp += string(buf[:n]) //累加读取的内容 }
fmt.Println("buf = ", string(tmp)) }
|