1.TCP编程
func main() {
//指定服务器通信协议、IP地址、端口号
listener, err := net.Listen("tcp", "127.0.0.1:8000")
if err != nil {
fmt.Println(err)
return
}
defer listener.Close() //关闭
//阻塞监听客户端连接请求
conn, err := listener.Accept()
if err != nil {
fmt.Println(err)
return
}
defer conn.Close() //关闭
//读取客户端发送的数据
buf := make([]byte, 4096)
n, err := conn.Read(buf)
if err != nil {
fmt.Println(err)
return
}
//处理数据
fmt.Println("服务器:", string(buf[:n]))
conn.Write([]byte("reply:" + string(buf[:n])))
}
func main() {
//指定服务器通信协议、IP地址、端口号
conn, err := net.Dial("tcp", "127.0.0.1:8000")
if err != nil {
fmt.Println(err)
return
}
defer conn.Close() //关闭
//主动写数据给服务器
conn.Write([]byte("hello world"))
//接收服务器回发的数据
buf := make([]byte, 4096)
n, err := conn.Read(buf)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(buf[:n]))
}
1.1并发版本
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)
data := string(buf[:n])
if strings.HasPrefix(strings.ToLower(data), "exit") {
fmt.Println("服务器检测到客户端[", addr, "]退出...")
return
} else if n == 0 {
fmt.Println("服务器检测到客户端[", addr, "]已关闭...")
return
} else if err != nil {
fmt.Println("conn.Read err:", err)
return
}
//处理数据
fmt.Println(addr, ",服务器读到数据:", data)
conn.Write([]byte("reply:" + data))
}
}
func main() {
//创建监听套接字
listener, err := net.Listen("tcp", "127.0.0.1:8000")
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)
}
}
func main() {
//主动发起连接请求
conn, err := net.Dial("tcp", "127.0.0.1:8000")
if err != nil {
fmt.Println("net.Dial err:", err)
return
}
defer conn.Close() //关闭
// 获取用户键盘输入( stdin ),将输入数据发送给服务器
go func() {
buf := make([]byte, 4096)
for {
n, err := os.Stdin.Read(buf)
if err != nil {
fmt.Println("os.Stdin.Read err:", err)
continue
}
//写给服务器, 读多少,写多少!
conn.Write(buf[:n])
}
}()
// 回显服务器回发的数据
buf := make([]byte, 4096)
for {
n, err := conn.Read(buf)
if n == 0 {
fmt.Println("客户端检测到服务器已关闭...")
return
} else if err != nil {
fmt.Println("conn.Read err:", err)
return
}
fmt.Println(string(buf[:n]))
}
}
2.UDP编程
func main() {
//组织一个udp地址结构
srvAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:8000")
if err != nil {
fmt.Println("net.ResolveUDPAddr err:", err)
return
}
fmt.Println("UDP服务器地址结构创建完成。")
//创建用于通信的socket
udpConn, err := net.ListenUDP("udp", srvAddr)
if err != nil {
fmt.Println("net.ListenUDP err:", err)
return
}
defer udpConn.Close() //关闭
fmt.Println("UDP服务器通信socket创建完成。")
//读取客户端发送的数据
buf := make([]byte, 4096)
//返回3个值,分别是读取到的字节数、客户端的地址、error
n, cltAddr, err := udpConn.ReadFromUDP(buf)
if err != nil {
fmt.Println("udpConn.ReadFromUDP err:", err)
return
}
//模拟处理数据
fmt.Printf("服务器读到 %v 的数据:%s\n", cltAddr, string(buf[:n]))
//回写数据给客户端
_, err = udpConn.WriteToUDP([]byte("replay:"+string(buf[:n])), cltAddr)
if err != nil {
fmt.Println("udpConn.WriteToUDP err:", err)
return
}
}
客户端 参考 TCP 客户端。net.Dial(“udp”, “server 的IP+port”)
func main() {
//指定服务器通信协议、IP地址、端口号
conn, err := net.Dial("udp", "127.0.0.1:8000")
if err != nil {
fmt.Println(err)
return
}
defer conn.Close() //关闭
//主动写数据给服务器
conn.Write([]byte("hello world"))
//接收服务器回发的数据
buf := make([]byte, 4096)
n, err := conn.Read(buf)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(buf[:n]))
}
2.1并发版本
服务器 UDP默认支持客户端并发访问,服务器处理 ReadFromUDP 和 WriteToUDP操作分开。提高并发效率。
func main() {
//组织一个udp地址结构
srvAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:8000")
if err != nil {
fmt.Println("net.ResolveUDPAddr err:", err)
return
}
fmt.Println("UDP服务器地址结构创建完成。")
//创建用于通信的socket
udpConn, err := net.ListenUDP("udp", srvAddr)
if err != nil {
fmt.Println("net.ListenUDP err:", err)
return
}
defer udpConn.Close() //关闭
fmt.Println("UDP服务器通信socket创建完成。")
//读取客户端发送的数据
buf := make([]byte, 4096)
for {
//返回3个值,分别是读取到的字节数、客户端的地址、error
n, cltAddr, err := udpConn.ReadFromUDP(buf)
if err != nil {
fmt.Println("udpConn.ReadFromUDP err:", err)
return
}
//模拟处理数据
fmt.Printf("服务器读到 %v 的数据:%s\n", cltAddr, string(buf[:n]))
go func() {
//回写数据给客户端
_, err = udpConn.WriteToUDP([]byte("replay:"+string(buf[:n])), cltAddr)
if err != nil {
fmt.Println("udpConn.WriteToUDP err:", err)
return
}
}()
}
}
func main() {
//指定服务器通信协议、IP地址、端口号
conn, err := net.Dial("udp", "127.0.0.1:8000")
if err != nil {
fmt.Println(err)
return
}
defer conn.Close() //关闭
//获取用户键盘输入数据
go func() {
buf := make([]byte, 4096)
for {
n, err := os.Stdin.Read(buf)
if err != nil {
fmt.Println("os.Stdin.Read err:", err)
continue
}
//主动写数据给服务器
conn.Write(buf[:n])
}
}()
buf := make([]byte, 4096)
for {
//接收服务器回发的数据
n, err := conn.Read(buf)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(buf[:n]))
}
}
3.文件传输
func SendFile(conn net.Conn, filePath string) {
//只读打开文件
file, err := os.Open(filePath)
if err != nil {
fmt.Println("os.Open err:", err)
return
}
defer file.Close()
//从本地文件中读数据,写给接收端。读多少写多少
buf := make([]byte, 4096)
for {
n, err := file.Read(buf)
if err != nil {
if err == io.EOF {
fmt.Println("发送文件完毕...")
} else {
fmt.Println("file.Read err:", err)
}
return
}
//写到网络socket中
_, err = conn.Write(buf[:n])
if err != nil {
fmt.Println("conn.Write err:", err)
return
}
}
}
func main() {
//go run Client.go D:\books\golang\netcat-win32-1.12.zip
list := os.Args //获取命令行参数
if len(list) != 2 {
fmt.Println("格式为:go run xxx.go 文件绝对路径")
return
}
//提取文件的绝对路径
filePath := list[1]
//提取文件名
fileInfo, err := os.Stat(filePath)
if err != nil {
fmt.Println("os.Stat err:", err)
return
}
fileName := fileInfo.Name()
//主动发起连接请求
conn, err := net.Dial("tcp", "127.0.0.1:8000")
if err != nil {
fmt.Println("net.Dial err:", err)
return
}
defer conn.Close()
//发送文件名给接收端
_, err = conn.Write([]byte(fileName))
if err != nil {
fmt.Println("conn.Write err:", err)
return
}
//读取服务器回发的数据
buf := make([]byte, 4096)
n, err := conn.Read(buf)
if err != nil {
fmt.Println("conn.Read err:", err)
return
}
//判断是否收到服务器回发的“ok”
data := string(buf[:n])
if strings.HasPrefix(strings.ToLower(data), "ok") {
//写文件内容给服务器
SendFile(conn, filePath)
}
}
func RecvFile(conn net.Conn, fileName string) {
//按照文件名创建新文件
file, err := os.Create(fileName)
if err != nil {
fmt.Println("os.Create err:", err)
return
}
defer file.Close()
//从网络中读数据,写入本地文件
buf := make([]byte, 4096)
for {
n, err := conn.Read(buf)
if n == 0 {
fmt.Println("接收文件完毕...")
return
} else if err != nil {
fmt.Println("conn.Read err:", err)
return
}
//写入本地文件,读多少写多少
file.Write(buf[:n])
}
}
func main() {
//创建用户监听的socket
listen, err := net.Listen("tcp", "127.0.0.1:8000")
if err != nil {
fmt.Println("net.Listen err:", err)
return
}
defer listen.Close()
//阻塞监听
conn, err := listen.Accept()
if err != nil {
fmt.Println("listen.Accept err:", err)
return
}
defer conn.Close()
//获取文件名,保存
buf := make([]byte, 4096)
n, err := conn.Read(buf)
if err != nil {
fmt.Println("conn.Read err:", err)
return
}
fileName := string(buf[:n])
//会写ok给发送端
_, err = conn.Write([]byte("ok"))
if err != nil {
fmt.Println("conn.Write err:", err)
return
}
//获取文件内容
RecvFile(conn, fileName)
}
4.HTTP编程
4.1http请求报文
func errFunc(info string, err error) {
if err != nil {
fmt.Println(info, err)
os.Exit(1)
}
}
func main() {
listener, err := net.Listen("tcp", "127.0.0.1:8000")
errFunc("net.Listen err:", err)
defer listener.Close()
conn, err := listener.Accept()
errFunc("listener.Accept err:", err)
defer conn.Close()
buf := make([]byte, 4096)
n, err := conn.Read(buf)
if n == 0 {
return
}
errFunc("conn.Read err:", err)
fmt.Printf("|%s|\n", string(buf[:n]))
}
|GET /favicon.ico HTTP/1.1
Host: 127.0.0.1:8000
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: __guid=96992031.1246173382985738200.1550026754561.2637; monitor_count=2
|
4.2http响应报文
func handler(resp http.ResponseWriter, req *http.Request){
resp.Write([]byte("hello world"))
}
func main() {
//注册回调函数,该回调函数会在服务器被访问时,自动调用。
http.HandleFunc("/test.do", handler)
//绑定服务器监听地址
http.ListenAndServe("127.0.0.1:8000", nil)
}
func errFunc2(info string, err error) {
if err != nil {
fmt.Println(info, err)
os.Exit(1)
}
}
func main() {
conn, err := net.Dial("tcp", "127.0.0.1:8000")
errFunc2("net.Dial err:", err)
defer conn.Close()
httpRequest := "GET /test.do HTTP/1.1\r\nHost:127.0.0.1:8000\r\n\r\n"
conn.Write([]byte(httpRequest))
buf := make([]byte, 4096)
n, err := conn.Read(buf)
if n == 0 {
return
}
errFunc2("conn.Read err:", err)
fmt.Printf("|%s|\n", string(buf[:n]))
}
|HTTP/1.1 200 OK
Date: Wed, 13 Feb 2019 03:08:51 GMT
Content-Length: 11
Content-Type: text/plain; charset=utf-8
hello world|
4.3HTTP服务端
用TCP来开发服务端,就是做web应用,类似发布到Tomcat上面那些。 用TCP来开发客户端,就是做类似爬虫那些。
func myHandler(resp http.ResponseWriter, req *http.Request) {
//从客户端读到的内容
fmt.Println("Header:", req.Header)
fmt.Println("URL:", req.URL)
fmt.Println("Method:", req.Method)
fmt.Println("Host:", req.Host)
fmt.Println("RemoteAddr:", req.RemoteAddr)
fmt.Println("Body:", req.Body)
//写给客户端的数据内容
url := req.URL.String()
if "/test" == url {
resp.Write([]byte("This Is A Web Server"))
} else if "/hello" == url {
resp.Write([]byte("Hello World"))
} else {
resp.Write([]byte("404 Page Not Found"))
}
}
func main() {
//注册回调函数,该回调函数会在服务器被访问时,自动调用。
//指定"/",则http://127.0.0.1:8000/* 都可以访问服务器
//指定"/project/",则http://127.0.0.1:8000/project/* 都可以访问服务器
http.HandleFunc("/", myHandler)
//绑定服务器监听地址
http.ListenAndServe("127.0.0.1:8000", nil)
}
4.4HTTP客户端
func main() {
//使用Get方法获取服务器响应包数据
//resp, err := http.Get("http://www.baidu.com")
resp, err := http.Get("http://127.0.0.1:8000/test")
if err != nil {
fmt.Println("http.Get err:", err)
return
}
defer resp.Body.Close()
// 获取服务器端读到的数据
fmt.Println("Status = ", resp.Status) // 状态
fmt.Println("StatusCode = ", resp.StatusCode) // 状态码
fmt.Println("Header = ", resp.Header) // 响应头部
fmt.Println("Body = ", resp.Body) // 响应包体
buf := make([]byte, 4096) // 定义切片缓冲区,存读到的内容
var result string
// 获取服务器发送的数据包内容
for {
n, err := resp.Body.Read(buf) // 读body中的内容。
if n == 0 {
fmt.Println("-> Read finish!")
break
}
if err != nil && err != io.EOF {
fmt.Println("resp.Body.Read err:", err)
return
}
result += string(buf[:n]) // 累加读到的数据内容
}
// 打印从body中读到的所有内容
fmt.Println("result = ", result)
}
Status = 200 OK
StatusCode = 200
Header = map[Date:[Wed, 13 Feb 2019 12:41:06 GMT] Content-Length:[20] Content-Type:[text/plain; charset=utf-8]]
Body = &{0xc0420f0240 {0 0} false <nil> 0x5cee00 0x5ceda0}
-> Read finish!
result = This Is A Web Server