1.网络编程基本介绍
Golang的主要设计目标之一就是面向大规模后端服务程序,网络通信这块是服务端程序必不可少也是至关重要的一部分
网络编程有两种:
1)TCP socket编程,是网络编程的主流。底层是基于TCP/IP协议的,例如QQ等客户端。
2)b/s结构(Browser/Server,浏览器/服务器模式)的是http编程,使用浏览器访问服务器时,使用的是http协议,而http底层依旧是用tcp socket实现的。比如京东
2.快速入门
服务器端的处理流程
1)监听端口【8888】
2)接收客户端的tcp链接,建立客户端和服务端的链接
3)创建foroutine,处理该链接的请求(通常客户端会通过链接发送请求包)
客户端的处理流程
1)建立与服务端的链接
2)发送请求数据【终端】,接收服务器端返回的结果数据
3)关闭链接
使用net包进行网络编程
package net :import "net"
net包提供了可移植的网络I/O接口,包括TCP/IP、UDP、域名解析和Unix域socket。
虽然本包提供了对网络原语的访问,大部分使用者只需要Dial、Listen和Accept函数提供的基本接口;以及相关的Conn和Listener接口。crypto/tls包提供了相同的接口和类似的Dial和Listen函数。
Listen函数创建的服务端:
ln, err := net.Listen("tcp", ":8080")
if err != nil {
// handle error
}
for {
conn, err := ln.Accept()
if err != nil {
// handle error
continue
}
go handleConnection(conn)
}
Dial函数使客户端和服务端建立连接:
conn, err := net.Dial("tcp", "google.com:80")
if err != nil {
// handle error
}
fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n")
status, err := bufio.NewReader(conn).ReadString('\n')
// ...
案例
写一个客户端和服务端,使客户端发送消息给客户端,输入一行发送一行,在客户端输入exit退出
server.go
package main
import (
"fmt"
"io"
"net"
)
func process(conn net.Conn) {
defer conn.Close()
for {
buf := make([]byte, 1024)
//1.等待客户端write数据给conn
//2.如果客户端没有发送数据,则堵塞在这里
//fmt.Printf("服务器在等待客户端%s,发送消息\n", conn.RemoteAddr().String())
n, err := conn.Read(buf) //从conn读取
if err == io.EOF {
fmt.Printf("客户端文件读取完毕退出\n")
return
}
//3.显示客户端发送的数据,将切片强制转换为string并截取buf的前n个数据
fmt.Printf(string(buf[:n]))
}
}
func main() {
listen, err := net.Listen("tcp", "0.0.0.0:8888")
if err != nil {
fmt.Printf("listen错误%v\n", err)
return
}
defer listen.Close() //延时关闭listen
//循环等待客户链接listen.Accept
for {
fmt.Println("等待有客户来链接...")
conn, err := listen.Accept()
if err != nil {
fmt.Printf("conn接收错误err=%v\n", err)
} else {
fmt.Printf("接收成功,conn:%v,客户端ip为%v\n", conn, conn.RemoteAddr().String())
}
go process(conn)
}
}
client.go
package main
import (
"bufio"
"fmt"
"net"
"os"
"strings"
)
func main() {
conn, err := net.Dial("tcp", "10.11.16.177:8888")
if err != nil {
fmt.Printf("服务器链接错误:%v\n", err)
return
}
fmt.Printf("链接服务器成功:%v\n", conn)
//功能一.客户端可以发送单行数据,然后退出
//1.新建bufio.NewReader 从标准输入os.Stdin接收数据 给reader
reader := bufio.NewReader(os.Stdin)
for {
//2.reader 读取数据直到碰到换行符'\n'
line, err := reader.ReadString('\n')
if err != nil {
fmt.Printf("writer.ReadString错误:%v\n", err)
}
//将line的换行符"\n"去掉
line = strings.Trim(line, "\n")
//输入exit为退出
if line == "exit" {
fmt.Println("退出写入")
break
}
//3.将读到的数据line传送给服务器
//给line加上换行符
_, err1 := conn.Write([]byte(line + "\n"))
if err1 != nil {
fmt.Printf("conn.Write错误:%v\n", err1)
}
}
//fmt.Printf("客户端发送了%v字节的数据,并退出\n", n)
}
3.海量用户即时通讯