- FD file descriptor 文件信息
- netFD 实现了各个系统对socket的封装
conn
该结构实现了Conn接口
type conn struct { fd *netFD }
conn的方法
- Read(b []byte) (n int, err error)
- 从连接中读取所有内容
result, err := ioutil.ReadAll(conn) //读取所有内容 //读取指定长度的内容 var buf [512]byte n, err := conn.Read(buf[0:]) //不断的从连接读取.. 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
- Write(b []byte) (n int, err error)
- 向连接中写入数据,n是写入数据的大小
_, err = conn.Write([]byte("GET / HTTP/1.0\r\n\r\n"))
- Close() error
- 关闭连接
- LocalAddr() Addr
- 获取发送连接的本地IP和端口
- RemoteAddr() Addr
- 获取目标主机的ip和端口
tcpAddr, err := net.ResolveTCPAddr("tcp4", "www.baidu.com:80") conn, err := net.DialTCP("tcp", nil, tcpAddr) fmt.Println(conn.LocalAddr()) // 192.168.1.88:51164 fmt.Println(conn.RemoteAddr()) // 220.181.111.147:80
- SetDeadline(t time.Time) error
- 设置连接到期时间,就是连接超时时间
- SetReadDeadline(t time.Time) error
- 设置连接读取到期时间
- SetWriteDeadline(t time.Time) error
- 设置连接写入到期时间
- SetReadBuffer(bytes int) error
- 设置操作系统连接相关接收缓冲区大小
- SetWriteBuffer(bytes int) error
- 设置操作系统连接相关传输缓冲区大小
- File() (f *os.File, err error)
- 返回网络文件信息
TCPConn
注意:该类型并没有实现PacketConn接口.这是和udp的不同
type TCPConn struct { conn }
DialTCP
一旦客户端已经建立TCP服务, 就可以和对方设备"通话"了. 如果成功,该调用返回一个用于通信的TCPConn。客户端和服务器通过它交换消息。通常情况下,客户端使用TCPConn写入请求到服务器, 并从TCPConn的读取响应。持续如此,直到任一(或两者)的两侧关闭连接。客户端使用DialTCP()该函数建立一个TCP连接。
DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error)
其中laddr是本地地址,通常设置为nil;raddr是一个服务的远程地址, net是一个字符串,根据您是否希望是一个TCPv4连接,TCPv6连接来设置为"tcp4", "tcp6"或"tcp"中的一个,当然你也可以不关心链接形式。
客户端可能发送的消息之一就是“HEAD”消息。这用来查询服务器的信息和文档信息。 服务器返回的信息,不返回文档本身。发送到服务器的请求可能是:
"HEAD / HTTP/1.1\r\n\r\n"
来吧看一个完整的栗子:
package main import ( "fmt" "io/ioutil" "net" "os" ) func main() { tcpAddr, err := net.ResolveTCPAddr("tcp4", "localhost:80") //换成www.baidu.com:80试一试 checkError(err) conn, err := net.DialTCP("tcp", nil, tcpAddr) checkError(err) _, err = conn.Write([]byte("GET / HTTP/1.0\r\n\r\n")) //发送http请求 checkError(err) result, err := ioutil.ReadAll(conn) checkError(err) fmt.Println(string(result)) os.Exit(0) } func checkError(err error) { if err != nil { fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error()) os.Exit(1) } }
TCPConn的方法
- ReadFrom(r io.Reader) (int64, error)
- 从一个IO中读取数据
- CloseRead() error
- CloseWrite() error
- SetLinger(sec int) error
- SetKeepAlive(keepalive bool) error
- 即使没有任何通信,一个客户端可能希望保持连接到服务器的状态。
- SetNoDelay(noDelay bool) error
- 设置操作系统是否延迟发送数据包,默认是无延迟的
TCPlistener
type TCPListener struct { fd *netFD }
ListenTCP
在一个服务器上注册并监听一个端口。然后它阻塞在一个"accept"操作,并等待客户端连接。当一个客户端连接, accept调用返回一个连接(connection)对象
net参数可以设置为字符串"tcp", "tcp4"或者"tcp6"中的一个。如果你想监听所有网络接口,IP地址应设置为0,或如果你只是想监听一个简单网络接口,IP地址可以设置为该网络的地址。如果端口设置为0,O/S会为你选择一个端口。否则,你可以选择你自己的。需要注意的是,在Unix系统上,除非你是监控系统,否则不能监听低于1024的端口,小于128的端口是由IETF标准化。该示例程序选择端口1200没有特别的原因。TCP地址如下":1200"
让我们看个完整的栗子
package main import ( "fmt" "net" "os" "time" ) func main() { tcpAddr, err := net.ResolveTCPAddr("tcp", ":1201") checkError(err) listener, err := net.ListenTCP("tcp", tcpAddr) checkError(err) for { conn, err := listener.Accept() if err != nil { continue } daytime := time.Now().String() conn.Write([]byte(daytime)) conn.Close() } } func checkError(err error) { if err != nil { fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error()) os.Exit(1) } }
相比客户端服务器更要注意对错误的处理。服务器应该永远运行,所以,如果出现任何错误与客户端,服务器只是忽略客户端继续运行。否则,客户端可以尝试搞砸了与服务器的连接,并导致服务器宕机。
TCPListener方法
- AcceptTCP() (c *TCPConn, err error)
- 接收TCP连接
- Accept() (c Conn, err error)
- 接收,返回一个连接
- Close() error
- 关闭监听
- Addr() Addr
- 返回监听的网络地址
- SetDeadline(t time.Time) error
- 设置监听到期时间
listener.SetDeadline(time.Now().Add(time.Second * 30))
- File() (f *os.File, err error)
关于长连接理论上的实现.
长连接,就是不断的连接.只要保证连接不断.服务端不断循环读取连接中的值,然后进行处理.发送结果就OK了.保持连接..发送.接受.