go语言网络编程(Socket编程)
Posted 开源你我
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go语言网络编程(Socket编程)相关的知识,希望对你有一定的参考价值。
一.go语言网络概述
go语言中,网络编程它提供一个net,支持基于IP层、TCP和UDP层及更高层(如HTTP,FTP、SMITP)的网络操作,其中IP层称为RawSocket。
二.Socket编程
在C++或者java这样语言中,socket编程是下面的这么一种方式:
Server端:
1.创建Socket,使用一个叫做Socket函数
2.绑定Socket,使用的是bind函数。
3.监听最大连接数,Listen函数
4.接受连接,使用accept函数
5.发送或者接收消息,recv和send类似函数,read和write类似功能的函数
Client端
1.创建Socket,使用一个叫做Socket函数
2.可以绑定IP或者端口,如果不绑定,会自动隐式绑定
3.连接服务器,用connect函数
4.接收或者发送消息,recv和send类似函数,read和write类似功能的函数
在go语言中,不是像上面的方式去写Socket编程的代码,go语言的标准库对此过程进行了抽象和封装,无论我们期望使用什么协议建立什么样的连接,都只需要调用net.Dial()就可以。
2.1.Dial函数
函数原型:
func Dial(net, addr string) (Conn, error)
参数说明:
net:网络协议的名字
返回值:
成功返回连接对象
失败返回错误
TCP的连接示例:
conn, err := net.Dial("tcp", "127.0.0.1:8888")
UDP的连接示例
conn, err := net.Dial("udp", "127.0.0.1:8888")
ICMP的连接示例
conn, err := net.Dial("ipv4:icmp", "127.0.0.1:8888")
目前,Dial函数支持一下几种网络协议:“tcp”, "tcp4", "tcp6";“udp”, "udp4", "udp6";"ip","ip4","ip6"
在成功建立连接后,我们就可以通过网络来收发数据了,使用Write和Read函数
icmp示例:
package main
import (
"net"
"os"
"fmt"
)
func main(){
conn, err := net.Dial("ip4:icmp", "www.baidu.com")
checkError(err)
var msg [512]byte
msg[0] = 8
msg[1] = 0
msg[2] = 0
msg[3] = 0
msg[4] = 0
msg[5] = 13
msg[6] = 0
msg[7] = 37
len := 8
check := checkSum(msg[0:len])
msg[2] = byte(check >> 8)
msg[3] = byte(check & 255)
_, err = conn.Write(msg[0:len])
checkError(err)
_, err = conn.Read(msg[0:])
checkError(err)
fmt.Println("Got response")
if msg[5] == 13 {
fmt.Println("Identifier Matcher")
}
if msg[7] == 37 {
fmt.Println("Sequece Matcher")
}
os.Exit(0)
}
func checkSum(msg []byte) uint16 {
sum := 0
//先假设为偶数
for n := 1; n < len(msg) - 1; n += 2 {
sum += int(msg[n])*256 + int(msg[n + 1])
}
sum = (sum >> 16) + (sum & 0xffff)
sum += (sum >> 16)
var answer uint16 = uint16(^sum)
return answer
}
func checkError(err error){
if err != nil {
fmt.Println(os.Stderr, "Fatal error : s%", err.Error())
os.Exit(0)
}
}
TCP案例
package main
// icmp
import (
"net"
"os"
"fmt"
"bytes"
"io"
)
func main(){
conn, err := net.Dial("tcp", "www.baidu.com:80")
checkError(err)
_, err = conn.Write([]byte("HEAD/HTTP/1.0\r\n\r\n"))
checkError(err)
ret, err := readFull(conn)
checkError(err)
fmt.Println(string(ret))
os.Exit(0)
}
func checkError(err error){
if err != nil {
fmt.Println(os.Stderr, "Fatal error : s%", err.Error())
os.Exit(0)
}
}
func readFull(conn net.Conn) ([]byte, error) {
defer conn.Close()
result := bytes.NewBuffer(nil)
var buf [512]byte
for {
n, err := conn.Read(buf[0:])
result.Write(buf[0:n])
if err != nil {
if err == io.EOF {
break
}
return nil, err
}
}
return result.Bytes(), nil
}
效果截图:
2.2.网络通信的其他控制原语
实际上,Dial函数是对DialTCP(),DialUDP(),DialIP()和DialUnix()的封装,当然,我们也可以直接使用这些函数。原型如下:
func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err error)
func DialUDP(net string, laddr, raddr *UDPAddr) (c *UDPConn, err error)
func DialIP(netProto string, laddr, raddr *IPAddr) (c *IPConn, err error)
func DialUnix(net string, laddr, raddr *UnixAddr) (c *UnixConn, err error)
完整示例代码:
package main
// icmp
import (
"net"
"os"
"fmt"
"io/ioutil"
)
func main(){
tcpAddr, err := net.ResolveTCPAddr("tcp4", "www.zgxnjz.cn:80")
conn, err := net.DialTCP("tcp", nil, tcpAddr)
checkError(err)
_, err = conn.Write([]byte("HEAD/HTTP/1.0\r\n\r\n"))
checkError(err)
ret, err := ioutil.ReadAll(conn)
checkError(err)
fmt.Println(string(ret))
os.Exit(0)
}
func checkError(err error){
if err != nil {
fmt.Println(os.Stderr, "Fatal error : s%", err.Error())
os.Exit(0)
}
}
结果截图:
以上是关于go语言网络编程(Socket编程)的主要内容,如果未能解决你的问题,请参考以下文章