网络编程有两种:
1)TCP socket编程,是网络编程的主流。之所以叫tcp socket编程,是因为底层是基于tcp/ip协议的,比如QQ聊天。
2)b/s结构的http编程,我们使用浏览器去访问服务器时,使用的就是http协议,而http底层依旧是tcp socket实现的。
tcp编程
服务端的处理流程
1)监听端口
2)接收客户端的tcp链接,建立客户端和服务器端的链接
3)创建goroutine,处理该链接的请求(通常客户端会通过链接发送请求包)
客户端的处理流程
1)建立与服务端的链接
2)发送请求数据,接收服务器端返回的结果数据
3)关闭链接
server.go
package main
import (
"fmt"
"net"
)
func process(conn net.Conn) {
//这里我们循环的接收客户端发送的数据
defer conn.Close()
for true {
//创建一个新的切片
buf := make([]byte, 1024)
//1.等待客户端通过conn发送信息
//2.如果客户端没有write[发送],那么协程就阻塞在这里
fmt.Println("服务器在等待客户端发送信息", conn.RemoteAddr())
n, err := conn.Read(buf) //从conn读取
if err != nil {
fmt.Println("客户端退出")
return
}
//3.显示客户端发送的内容到服务器的终端
fmt.Print(string(buf[:n]))
}
}
func main() {
fmt.Println("服务器开始监听。。。")
//1.tcp表示使用网络协议是tcp
//2. 0.0.0.0:8888表示在本地监听端口8888
listen, err := net.Listen("tcp", "0.0.0.0:9999")
if err != nil {
fmt.Println("listen err=", err)
return
}
defer listen.Close() //延时关闭listen
//循环等待客户端来连接我
for true {
//等待客户端连接
fmt.Println("等待客户端连接")
conn, err := listen.Accept()
if err != nil {
fmt.Println("accept() err=", err)
} else {
fmt.Printf("accept() suc con=%v 客户端ip=%v\n", conn, conn.RemoteAddr())
}
//这里准备起一个协程,为客户端服务
go process(conn)
}
fmt.Printf("listen suc=%v\n", listen)
}
client.go
package main
import (
"bufio"
"fmt"
"net"
"os"
"strings"
)
func main() {
conn, err := net.Dial("tcp", "127.0.0.1:9999")
if err != nil {
fmt.Println("client dail err=", err)
return
} else {
fmt.Println("conn 成功=", conn)
}
for true {
//功能一:客户端可以发送单行数据,然后就退出
reader := bufio.NewReader(os.Stdin) //os.stdin 代表标准输入【终端】
//从终端读取一行用户输入,并准备发送给服务器
line, err := reader.ReadString('\n')
if err != nil {
fmt.Println("readstring err=", err)
}
line = strings.Trim(line, "\r\n")
//fmt.Println(line[:len(line)-2])
if line == "exit" {
fmt.Println("退出")
return
}
//再将line发送给服务器
n, err := conn.Write([]byte(line))
if err != nil {
fmt.Println("conn.Write err=", err)
}
fmt.Printf("客户端发送了%d字节的数据\n", n)
}
}