目录
GO的网络编程
客户端和服务端模型
七层模型
socket: BSD UNIX的进程通信机制,通常也称作'套接字”,用于描述IP地址和端口,是一个通信链的句柄。socket可以理解为TCP/IP网络的API,它定义了许多函数,程序员可以使用它来开发TCP/IP网络的应用程序。计算机上运行对应用程序通常通过“套接字”向网络发出请求或者应答网络请求。
服务端处理流程;
1)监听端口
2)接收客户端连接
3)创建goroutine,处理此连接
客户端处理流程:
1)建立与服务端连接
2)进行数据收发
3)关闭连接
Apache是同步模型,Nginx是异步模型
TCP通信
server端
一个TCP服务端可以同时连接很多个客户端,例如世界各地的用户使用自己电脑上的浏览器访问淘宝网。因为Go语言中创建多个goroutine实现并发非常方便和高效,所以我们可以每建立一次链接就创建一个goroutine去处理。
package main
import (
"fmt"
"net"
)
//处理客户端连接
func proe(conn net.Conn) {
//关闭conn资源
defer conn.Close()
//定义接受字节数组
var buf [1024]byte
//获取有效数据
n,err :=conn.Read(buf[:])
if err!=nil {
fmt.Println("获取信息失败,err:",err)
return
}
fmt.Printf("收到客户端信息是:%s",string(buf[:n]))
}
func main() {
listener,err := net.Listen("tcp","127.0.0.1:20000")
if err != nil {
fmt.Println("服务启动失败")
return
}
defer listener.Close()
//建立连接
for {
conn , err :=listener.Accept()
if err!=nil {
fmt.Println("接受信息失败",err)
continue
}
//启动goroutine
go proe(conn)
}
}
client端
package main
import (
"bufio"
"fmt"
"net"
"os"
)
//TCP客户端配置
func main() {
//1、使用拨号方式链接服务器
conn, err := net.Dial("tcp", "127.0.0.1:20000")
if err != nil {
fmt.Println("连接服务器失败,err:", err)
return
}
//关闭连接
defer conn.Close()
reader := bufio.NewReader(os.Stdin)
for {
input, err := reader.ReadString('\n')
if input == "q\r\n" {
return
}
if err != nil {
fmt.Println("控制台输入失败,err", err)
return
}
//向服务器发送信息
_, err = conn.Write([]byte(input))
if err != nil {
fmt.Println("信息发送失败,err:", err)
return
}
}
}
最后效果,先起service端,再起客户端
聊天模式
服务端
package main
import (
"fmt"
"net"
)
//var ConnMap map[string]*net.TCPConn
func main() {
listen_socket, err := net.Listen("tcp", "127.0.0.1:20000") //打开监听接口
if err != nil { //如果有错误
fmt.Println("服务器连接失败")
return
}
defer listen_socket.Close() //延迟服务器端关闭
fmt.Println("服务器运行中....")
for {
conn, err := listen_socket.Accept() //监听客户端的端口
if err != nil {
fmt.Println("客户端开始失败")
}
fmt.Println("连接服务器成功") //显示服务器端连接成功
var msg string //声明msg为字符串变量
for {
//开始接收客户端发过来的消息
msg = "" //字符串msg初始为空
data := make([]byte, 255) //创建并声明数据变量,为255位
msg_read, err := conn.Read(data) //接收由客户端发来的消息,字节赋值给msg_read,err为错误
if msg_read == 0 || err != nil { //如果读取的消息为0字节或者有错误
fmt.Println("err")
}
msg_read_str := string(data[0:msg_read]) //将msg_read_str的字节格式转化成字符串形式
if msg_read_str == "close" { //如果接收到的客户端消息为close
conn.Write([]byte("close"))
break
}
//fmt.Println(string(data[0:msg_read]))
fmt.Println("客户端给服务器发送消息 ", msg_read_str) //接收客户端发来的信息
fmt.Printf("对客户端发送消息: ") //提示向客户端要说的话
fmt.Scan(&msg) //输入服务器端要对客户端说的话
//conn.Write([]byte("hello client\n"))
//msg_write := []byte(msg)
conn.Write([]byte(msg)) //把消息发送给客户端
//此处造成服务器端的端口堵塞
}
//fmt.Println("client Close\n")
conn.Close() //关闭连接
}
}
client端
// One-to-one ChatRoom Client
package main
import (
"fmt"
"net"
)
func main() {
conn, err := net.Dial("tcp", "127.0.0.1:20000")
if err != nil {
fmt.Println("连接失败")
return
}
defer conn.Close()
fmt.Println("连接成功")
var msg string //声明msg为字符串变量
for {
msg = "" //初始化msg为空值
fmt.Printf("给服务器发送消息: ")
fmt.Scan(&msg) //输入客户端向服务器端要发送的消息
//fmt.Println(msg)
//msg_write := []byte(msg)
//conn.Write(msg_write)
conn.Write([]byte(msg)) //信息转化成字节流形式并向服务器端发送
//此处造成客户端程序端口堵塞
//fmt.Println([]byte(msg))
//等待服务器端发送信息回来
data := make([]byte, 255)
msg_read, err := conn.Read(data)
if msg_read == 0 || err != nil {
fmt.Println("err")
}
msg_read_str := string(data[0:msg_read])
if msg_read_str == "close" {
conn.Write([]byte("close"))
break
}
fmt.Println("服务器回应:", msg_read_str)
}
conn.Close()
}
运行结果
UDP编程
UDP是用户数据报协议,是一种无连接传输协议,不需要建立连接就可以直接发送和接收数据,属于不可靠的,没有时序的通信,UDP实时性好,适合直播环境。
服务器配置
package main
import (
"fmt"
"net"
)
func Porecss(listener *net.UDPConn) {
//退出是关闭资源
defer listener.Close()
var b string
for {
//获取连接输出
var buf [1024]byte
n, addr, err := listener.ReadFromUDP(buf[:])
if err != nil {
fmt.Println("读取udp失败err=", err)
return
}
//信息输出
fmt.Printf("来自%v的回复,内容是%v\n", addr, string(buf[:n]))
//信息回复
fmt.Println("给客户端回复")
fmt.Scan(&b)
_, err = listener.WriteToUDP([]byte(b), addr)
if err != nil {
fmt.Println("回复失败err=", err)
return
}
}
}
func main() {
listener, err := net.ListenUDP("udp", &net.UDPAddr{
IP: net.ParseIP("0.0.0.0"),
Port: 38080,
})
if err != nil {
fmt.Println("连接异常,err=", err)
}
Porecss(listener)
}
客户端配置
package main
import (
"fmt"
"net"
)
func main() {
conn, err := net.Dial("udp", "127.0.0.1:38080")
if err != nil {
fmt.Println("连接服务器失败,err:", err)
return
}
defer conn.Close()
//发送消息
var a string
for {
fmt.Println("输入要发送的信息")
fmt.Scan(&a)
_, err = conn.Write([]byte(a))
if err != nil {
fmt.Println("信息发送失败,err", err)
return
}
//接受消息
var buf [1024]byte
n, err := conn.Read(buf[:])
if err != nil {
fmt.Println("读取失败,err", err)
return
}
fmt.Println("收到服务端的信息是:", string(buf[:n]))
}
}