Go入门系列(十)网络
2020-03-18 本文已影响0人
RabbitMask
目录
一、TCP编程
二、UDP编程
其实前几天买了本书,今天终于到货了,满怀欣喜的打开目录,socket编程、数据库、I/O统统没有,额。。。
回归正题,关于TCP/UDP的基础我们不做过多解释了,大家可自行补充或可参考python网络编程【python入门系列(十)】辅助理解,才不是打广告的说。
一、TCP编程
我们借助net包来模拟一个系统,服务端可以相应来自用户端的输入,借助我们之前学到的并发,允许它为多个用户提供连接,且通过循环持续响应用户请求,在收到exit时断开连接:
- Server
Server端借助net包的Listen()方法创建监听:
func Listen(network, address string) (Listener, error)
//network:选用的协议:TCP、UDP, 如:“tcp”或 “udp” 注意:只支持小写字母
//address:IP地址+端口号, 如:“127.0.0.1:8000”或 “:8000”
数据交互时,发送使用Write()方法,接收使用Read()方法。
func main() {
listener, err := net.Listen("tcp", "127.0.0.1:8000")
checkErr(err)
defer listener.Close()
for {
conn, err := listener.Accept()
checkErr(err)
go task(conn)
}
}
func task(conn net.Conn) {
defer conn.Close()
addr := conn.RemoteAddr( ).String()
fmt.Println(addr, " connect sucessful" )
buf := make([ ]byte, 1024)
for{
n, err := conn.Read(buf)
checkErr(err)
if string(buf[:n])=="exit"{
conn.Write([]byte("拜拜~~~~"))
conn.Close()
fmt.Println(addr, " Disconnect sucessful" )
return
}
fmt.Printf("read buf = %s\n", string(buf[:n]))
response:="Hello "+string(buf[:n])
conn.Write([]byte(response))
}
}
func checkErr(err error) {
if err != nil {
fmt.Println(err.Error())
return
}
}
#控制台
127.0.0.1:54815 connect sucessful
read buf = rabbit
read buf = carrot
127.0.0.1:54815 Disconnect sucessful
我们稍加总结下最重要的数据交互规则:
func taskdemo(c net.Conn) {
//some code...
//Simple read from connection
buffer := make([]byte, 1024)
c.Read(buffer)
//simple write to connection
c.Write([]byte("Hello from server"))
}
- Client
CIient端用到的方法几乎与server端一致,创建服务器连接依赖net包的Dial()方法:
func Dial(network, address string) (Conn, error)
//network:选用的协议:TCP、UDP,如:“tcp”或 “udp”
//address:服务器IP地址+端口号, 如:“127.0.0.1:8000”或 “www.baidu.com:80”
func main() {
conn, err := net.Dial("tcp", "127.0.0.1:8000")
if err != nil {
fmt.Println("连接失败,错误:", err)
return
}
defer conn.Close()
for{
var name string
_, _ = fmt.Scanln(&name)
conn.Write([]byte(name))
buf := make([]byte,1024)
n,_ := conn.Read(buf)
fmt.Println(string(buf[:n]))
}
}
#控制台
rabbit
Hello rabbit
carrot
Hello carrot
exit
拜拜~~~~
二、UDP编程
UDP连接是一个不负责任的连接,如果不允许你的消息丢包,那记得做好接收反馈,如果没有接收成功记得重发,但是UDP的特点在于它不需要持续的会话,意味着在某些场景下他更加隐匿,比如木马、木马、和木马。
- Server
UDP编程Server端借助net包的ListenUDP()方法,数据交互读取使用ReadFromUDP()方法,发送使用WriteToUDP()方法,关于其并发的处理位置我们借助实例体会:
func main() {
udpAddr, _ := net.ResolveUDPAddr("udp", "127.0.0.1:8000")
listener, err := net.ListenUDP("udp", udpAddr)
checkErr(err)
fmt.Println("Start listening ... ")
defer listener.Close()
task(listener)
}
func task(conn *net.UDPConn) {
defer conn.Close()
buf := make([ ]byte, 1024)
for{
n, addr, err := conn.ReadFromUDP(buf)
checkErr(err)
fmt.Printf("read buf = %s\n", string(buf[:n]))
go func(){
response:="Hello "+string(buf[:n])
conn.WriteToUDP([]byte(response),addr)
}()
}
}
func checkErr(err error) {
if err != nil {
fmt.Println(err.Error())
return
}
}
#控制台
Start listening ...
read buf = rabbit
read buf = carrot
我们将UDP的并发处理放到了闭包这里,另外我们对数据交互的规则简单整理下:
func taskdemo(c *net.UDPConn) {
//some code...
//simple read
buffer := make([]byte, 1024)
n, addr, err:= c.ReadFromUDP(buffer)
//simple write to connection
c.WriteToUDP([]byte("Hello from server"),addr)
}
- Client
如果我们偷懒,直接使用tcp的client是完全可以的,把tcp修改为udp:
func main() {
conn, err := net.Dial("udp", "127.0.0.1:8000")
if err != nil {
fmt.Println("连接失败,错误:", err)
return
}
defer conn.Close()
for{
var name string
_, _ = fmt.Scanln(&name)
conn.Write([]byte(name))
buf := make([]byte,1024)
n,_ := conn.Read(buf)
fmt.Println(string(buf[:n]))
}
}
#控制台
rabbit
Hello rabbit
carrot
Hello carrot
当然,像服务端一样,使用ReadFromUDP()方法和WriteToUDP()方法也是可以的。