net包使用
net包主要是围绕三大数据类型做衍生的,如下:
type Addr
type Listener
type Conn
1、Listen函数
返回在一个本地网络地址laddr上监听的Listener。网络类型参数net必须是面向流的网络:"tcp"、"tcp4"、"tcp6"、"unix"或"unixpacket",因为是在服务器端使用,必须建立连接,面向包的udp是无连接的,所以listen函数net参数不支持udp。参见Dial函数获取laddr的语法
func Listen(network, address string) (Listener, error) {
addrs, err := DefaultResolver.resolveAddrList(context.Background(), "listen", network, address, nil)
if err != nil {
return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: nil, Err: err}
}
var l Listener
switch la := addrs.first(isIPv4).(type) {
case *TCPAddr:
l, err = ListenTCP(network, la)
case *UnixAddr:
l, err = ListenUnix(network, la)
default:
return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: address}}
}
if err != nil {
return nil, err // l is non-nil interface containing nil pointer
}
return l, nil
}
Listen函数用于获取一个监听器,相当与一个包装以下三个函数的函数 :
socket()
bind()
listen()
2、Accept方法
Accept方法属于net.Listener类型的方法,在调用时流程会阻塞,直到某个计算机上的某个应用程序与当前程序建立了一个tcp连接。此时accept方法会返回连个值,一个net.Conn类型值,一个error类型值
Accept() (Conn, error)
3、client 端函数 Dial函数和 DialTimeout函数
在网络network上连接地址address,并返回一个Conn接口。可用的网络类型有:"tcp"、"tcp4"、"tcp6"、"udp"、"udp4"、"udp6"、"ip"、"ip4"、"ip6"、"unix"、"unixgram"、"unixpacket"
对TCP和UDP网络,地址格式是host:port或[host]:port,参见函数JoinHostPort和SplitHostPort
等价于一个包装以下三个函数的函数:
socket()
bind()
connect
函数原型:
func Dial(network, address string) (Conn, error)
func DialTimeout(network, address string, timeout time.Duration) (Conn, error)
4、Conn类型
Conn接口代表通用的面向流的网络连接。多个线程可能会同时调用同一个Conn的方法。
type Conn interface {
// Read从连接中读取数据
// Read方法可能会在超过某个固定时间限制后超时返回错误,该错误的Timeout()方法返回真
Read(b []byte) (n int, err error)
// Write从连接中写入数据
// Write方法可能会在超过某个固定时间限制后超时返回错误,该错误的Timeout()方法返回真
Write(b []byte) (n int, err error)
// Close方法关闭该连接
// 并会导致任何阻塞中的Read或Write方法不再阻塞并返回错误
Close() error
// 返回本地网络地址
LocalAddr() Addr
// 返回远端网络地址
RemoteAddr() Addr
// 设定该连接的读写deadline,等价于同时调用SetReadDeadline和SetWriteDeadline
// deadline是一个绝对时间,超过该时间后I/O操作就会直接因超时失败返回而不会阻塞
// deadline对之后的所有I/O操作都起效,而不仅仅是下一次的读或写操作
// 参数t为零值表示不设置期限
SetDeadline(t time.Time) error
// 设定该连接的读操作deadline,参数t为零值表示不设置期限
SetReadDeadline(t time.Time) error
// 设定该连接的写操作deadline,参数t为零值表示不设置期限
// 即使写入超时,返回值n也可能>0,说明成功写入了部分数据
SetWriteDeadline(t time.Time) error
}
4、Read方法
func (c *TCPConn) Write(b []byte) (int, error)
5、Write方法
func (c *TCPConn) Write(b []byte) (int, error)
6、Close方法
func (c *TCPConn) Close() error
7、LocalAddr 和 RemoteAddr方法
func (c *TCPConn) LocalAddr() Addr //LocalAddr返回本地网络地址
func (c *TCPConn) RemoteAddr() Addr //RemoteAddr返回远端网络地址
8、SetDeadline、SetReadDeadline、SetWriteDeadline
func (c *TCPConn) SetDeadline(t time.Time) error //SetDeadline设置读写操作期限,实现了Conn接口的SetDeadline方法
func (c *TCPConn) SetReadDeadline(t time.Time) error //SetReadDeadline设置读操作期限,实现了Conn接口的SetReadDeadline方法
unc (c *TCPConn) SetWriteDeadline(t time.Time) error //SetWriteDeadline设置写操作期限,实现了Conn接口的SetWriteDeadline方法
9、ParseIP函数将string类型的ip地址转换为IP对象
type IP []byte //IP类型是代表单个IP地址的[]byte切片。本包的函数都可以接受4字节(IPv4)和16字节(IPv6)的切片作为输入
func ParseIP(s string) IP
type IPMask []byte //IPMask代表一个IP地址的掩码
代码事例:
package main
import (
"net"
"fmt"
"os"
)
func main(){
ipS := "192.168.1.97"
//将字符串解析为ip地址,并返回并返回该地址,如果s不是合法的IP地址文本表示,ParseIP会返回nil
ip := net.ParseIP(ipS)
if ip == nil {
fmt.Fprintf(os.Stderr, "ipS err: 地址是无效的 \n")
}
fmt.Print(ip , "\n")
//根据IP和掩码获得网络
mask := ip.DefaultMask()
network := ip.Mask(mask)
fmt.Printf("ip: %s, mask: %s, network: %s \n", ip, mask.String(), network.String())
}
10、将域名解析为ip地址
ResolveTCPAddr将addr作为TCP地址解析并返回。参数addr格式为"host:port"或"[ipv6-host%zone]:port",解析得到网络名和端口名;net必须是"tcp"、"tcp4"或"tcp6"。
IPv6地址字面值/名称必须用方括号包起来,如"[::1]:80"、"[ipv6-host]:http"或"[ipv6-host%zone]:80"
func ResolveTCPAddr(net, addr string) (*TCPAddr, error)
代码事例:
domain := "www.baidu.com:8080"
addr, err := net.ResolveTCPAddr("tcp", domain)
if err != nil {
fmt.Printf("err: %s", err)
return
}
fmt.Print(addr)
11、使用案例
服务端 service:
package main
import (
"net"
"log"
"io/ioutil"
"fmt"
)
func clientHandler(conn net.Conn) {
defer conn.Close()
//向客户端读取数据
params, err := ioutil.ReadAll(conn)
if err != nil {
log.Fatal(err)
}
fmt.Print(string(params))
//向客户端发送数据
n, err := conn.Write([]byte("hello,client \r\n"))
if err != nil {
log.Fatal(err)
}
fmt.Print(n)
}
func main() {
listen, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatal(err)
}
for {
conn, err := listen.Accept()
if err != nil {
fmt.Print(err)
continue
}
go clientHandler(conn)
}
}
客户端 client:
package main
import (
"net"
"log"
"io/ioutil"
"fmt"
)
func main() {
conn, err := net.Dial("tcp", ":8080")
if err != nil {
log.Fatal(err)
}
//向服务器发送数据
n, err := conn.Write([]byte("GET / HTTP/1.1 \r\n\r\n"))
if err != nil {
log.Fatal(err)
}
//向服务器读取数据
res, err := ioutil.ReadAll(conn)
if err != nil {
log.Fatal(err)
}
fmt.Printf("response: %s, write byte num: %d", string(res), n)
conn.Close()
}