net 包里的一些方法
-
ParseIP(string) // 验证IP地址字符串 返回 IP 对象
-
type IPMask []byte // 子网掩码类型
func IPv4Mask(a, b, c, d byte) IPMask // 用一个四字节的IPv4地址来创建一个掩码 func (ip IP) DefaultMask() IPMask // 这是一个IP方法,返回默认的掩码 func (ip IP) Mask(mask IPMask) IP // 一个掩码可以使用一个IP地址的方法,找到该IP地址的网络
-
在 net 包的许多函数和方法会返回一个指向IPAddr 的指针,这不过只是一个包含IP类型的结构体, 这种类型的主要
用途是通过 IP 主机名执行 DNS 查找type IPAddr struct { IP IP Zone string // IPv6 scoped addressing zone } func ResolveIPAddr(net, addr string) (*IPAddr, error) // 通过域名 返回主机IP func LookupHost(host string) (addrs []string, err error) // 一个域名可能有多个地址
-
服务运行在主机上,一个主机可以运行多个服务 (TCP, UDP, SCTP …) 使用端口来加以区分(1 ~ 65535)
- unix 系统中, /etc/service 文件列出了常用的端口, go 有一个函数可以获取该文件
func LookupPort(network, service string) (port int, err error)
- unix 系统中, /etc/service 文件列出了常用的端口, go 有一个函数可以获取该文件
-
TCPAddr 类型包含一个IP 和 一个 port 的结构 :
type TCPAddr struct { IP IP Port int } func ResolveTCPAddr(net, addr string) (*TCPAddr, error) // 创建一个 TCPAddr addr-www.baidu.com:80
-
TCP Sockets
func (c *TCPConn) Write(b []byte) (n int, err error)
func (c *TCPConn) Read(b []byte) (n int, err error) // 底层实际上还是调用 ReadFile 方法 读取 TCPConn 句柄里的数据到 b 切片里 e := ReadFile(fd, p, &done, nil) fd - TCPConn 以下 Read 方法跟这个一样
func DialTCP(net string, laddr, raddr *TCPAddr) // net-(tcp4,tcp6,tcp) laddr-nil
-
TCP 通信
func main(){ service := "127.0.0.1:8099" tcpAddr, err := net.ResolceTCPAddr("ip4", service) // 传入域名:端口 / IP:端口 返回一个TCP类型 listener, err := net.ListenTCP("tcp", tcpAddr) // 监听端口 也可以直接用 net.Listen("tcp", "127.0.0.1:8099") 来监听端口 for {//不间断的接受客户端请求 conn, err := listener.Accept() // 这步会阻塞到这 直到有客户端请求 if err != nil { continue } go handleClient(conn) // 多线程处理客户端请求 } } func handleClient(conn net.Conn) { defer conn.Close() var buf [512]byte for { n, err := conn.Read(buf[0:]) _, err = conn.Write(buf[0:n]) } }
-
超时
- 服务端会断开那些超时的客户端,如果他们响应的不够快,比如没有及时的往服务端写一个请求。
func (c *TCPConn) SetTimeout(nsec int64) error // 用在套接字读写前(Accept)
- 服务端会断开那些超时的客户端,如果他们响应的不够快,比如没有及时的往服务端写一个请求。
-
存活状态
- 即使没有任何通信 一个客户端可能希望保持连接到服务器的状态
func (c *TCPConn) SetKeepAlive(keepalive bool) error
- 即使没有任何通信 一个客户端可能希望保持连接到服务器的状态
-
-
UDP 通信
- 主要方法
func ResolveUDPAddr(net, addr string) (*UDPAddr, error) // 解析地址 生成 UDPAddr 类型 func DialUDP(net string, laddr, raddr *UDPAddr) // 连接 UDP服务器 func ListenUDP(net string, laddr *UDPAddr) (c *UDPConn, err error) // UDP协议监听端口 func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) // 处理客户端传过来的数据 func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (n int, err error) // 发送数据给客户端 func (c *conn) Write(b []byte) (int, error) // 发送数据给服务端 func (c *conn) Read(b []byte) (int, error) // 读取服务端发送过来的数据
- 主要方法
TCP 简单实现
- 服务端 这个跟上面的一样
func main(){
service := "127.0.0.1:8099"
tcpAddr, err := net.ResolceTCPAddr("ip4", service) // 传入域名:端口 / IP:端口 返回一个TCP类型
listener, err := net.ListenTCP("tcp", tcpAddr) // 监听端口 也可以直接用 net.Listen("tcp", "127.0.0.1:8099") 来监听端口
for {//不间断的接受客户端请求
conn, err := listener.Accept() // 这步会阻塞到这 直到有客户端请求
if err != nil {
continue
}
go handleClient(conn) // 多线程处理客户端请求
}
}
func handleClient(conn net.Conn) {
defer conn.Close()
var buf [512]byte
for {
n, err := conn.Read(buf[0:])
_, err = conn.Write(buf[0:n])
}
}
- 客户端简单实现 ~ 简化版
fmt.Println("please input host:port -")
var host string
fmt.Scanf("%s\n", &host)
tcpAddr,err := net.ResolveTCPAddr("tcp4", host)
conn, err := net.DialTCP("tcp", nil, tcpAddr)
bt, err := ioutil.ReadAll(conn)
if err != nil {
fmt.Println("one : ", err)
}
fmt.Println(string(bt))
result, err := ioutil.ReadAll(conn)
fmt.Println("获取到的数据是 : \n", string(result))
UDP 简单实现
- 服务端
addr := "127.0.0.1:8097"
udpAddr, err := net.ResolveUDPAddr("udp4", addr) // 生成 UDPAddr 类型
if err != nil {
fmt.Println("udp addr resolve err : ", err)
}
conn, err := net.ListenUDP("udp4", udpAddr) // 开启 UDP服务 监听端口
if err != nil {
fmt.Println("udp listen failed : ", err)
}
var buf [512]byte
for {
n, clientAddr, err := conn.ReadFromUDP(buf[0:]) // 读取客户端发送过来的数据 clientAddr-客户端地址 UDP相比TCP不需要三次握手 是迅速、无状态的,每次请求都会带上自己的IP等标识信息
if err != nil {
fmt.Println("udp read failed : ", err)
}
fmt.Println("get client data : ", string(buf[0:n]))
_, err = conn.WriteToUDP([]byte(time.Now().String()), clientAddr) // 发送数据给客户端
if err != nil {
fmt.Println("write udp failed : ", err)
}
}
- 客户端
addrPort := "127.0.0.1:8097"
udpAddr,err := net.ResolveUDPAddr("udp4", addrPort) // 把域名:端口 / IP:端口 解析成 UDPAddr 类型
if err != nil {
fmt.Println("UDPAddr trans failed", err)
}
conn, err := net.DialUDP("udp4", nil, udpAddr) // 连接服务器
if err != nil {
fmt.Println("udp 连接错误", err)
}
var buf [512]byte
for{
_, err = conn.Write([]byte("hello zzh")) // 发送数据给UDP服务器
if err != nil {
fmt.Println("udp 发送数据失败", err)
}
n, err := conn.Read(buf[0:]) // 读取服务器发送的数据
if err != nil {
fmt.Println("read udp failed : ", err)
}
fmt.Println("client get data : ", string(buf[0:n]))
time.Sleep(2e9)
关联文章 - OSI七层模型的理解