TCPConn
在Go语言中,net
包中有一个类型成为TCPConn
,这个类型可以用来作为客户端和服务器的交互通道,其中的主要函数为:
func (c *TCPConn) Write(b []byte) (n int, err os.Error)
func (c *TCPConn) Read(b []byte) (n int, err os.Error)
通过函数的名称可以看出来,这两个函数主要负责的是在客户端和服务器端读写数据。
当然,我们在使用这两个函数的时候还需要知道一个TCPAdrr
类型,也就是一个TCP
的地址信息:
type TCPAddr struct {
IP IP
Port int
Zone string // IPv6范围寻找区域
}
那我们应该如果获取TCPAddr
呢?
func ResolveTCPAddr(net, addr string) (*TCPAddr, os.Error)
其中,net
的参数可以TCP4
,TCP6
,TCP
中的任意一个,分别代表的是IPv4,IPv6,或者是两者其中的任意一个。addr
则表示的是域名或者IP地址。
TCP客户端
在Go语言中,我们使用net
中的DialTCP
来建立一个TCP
连接,具体函数定义如下:
func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPAddr, err os.Error)
net
参数是和前面的ResolveTCPAddr
函数是一样的,laddr
表示的本机地址,raddr
表示的远程服务地址。
我们可以通过下面的一个例子来模拟HTTP协议客户端请求去连接一个Web服务器端:
package main
import (
"fmt"
"io/ioutil"
"net"
"os"
)
func main() {
if len(os.Args) != 2 {
fmt.Fprintf(os.Stderr, "Useage: %s host:port ", os.Args[0])
os.Exit(0)
}
service := os.Args[1]
tcpAddr, err := net.ResolveTCPAddr("tcp4", service)
checkError(err)
conn, err := net.DialTCP("tcp", nil, tcpAddr)
checkError(err)
_, err = conn.Write([]byte("HEAD / HTTP/1.0\r\n\r\n"))
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, " Wrong: %s", err.Error())
os.Exit(1)
}
}
通过上面的程序可以很容易的看出来整个程序的执行顺序。
TCP服务器端
其实我们除了使用TCP编写客户端,还可以使用net
包来创建一个服务器端程序,在这里我们需要对端口进行监听,当有客户端请求到达的时候可以接收到来自客户端连接的请求。相关函数如下:
func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err os.Error)
func (l *TCPListener) Accept() (c Conn, err os.Error)
相关参数说明和DialTCP
的参数一样。下面我们来实现一个简单的时间同步服务,用来监听8000这一个端口:
package main
import (
"fmt"
"log"
"net"
"time"
)
func echo(conn *net.TCPConn) {
tick := time.Tick(5 * time.Second)
for now := range tick {
n, err := conn.Write([]byte(now.String()))
if err != nil {
log.Println(err)
conn.Close()
return
}
fmt.Printf("send %d bytes to %s\n", n, conn.RemoteAddr())
}
}
func main() {
address := net.TCPAddr{
IP:net.ParseIP("127.0.0.1"),
Port:8000,
}
listener, err := net.ListenTCP("tcp4", &address) // 创建TCP4服务器端监听器
if err != nil {
log.Fatal(err) // Println + os/Exit(1)
}
for {
conn, err := listener.AcceptTCP()
if err != nil {
log.Fatal(err) // 遇到错误直接退出
}
fmt.Println("Remote Address: ", conn.RemoteAddr())
go echo(conn)
}
}
该程序在执行后,他将会一直在那里等待,直到有新的客户端请求到达。当有新的客户端请求到达并同意接受该请求的时候它会反馈当前的时间信息。
控制TCP连接
TCP
当中是有很多连接控制函数的,最常用的有如下几个:
func DialTimeout(net, addr string, timeout time.Duration) (Conn, error)
设置建立连接的超时时间;
func (c *TCPConn) SetReadDeadline(t time.Time) error
func (c *TCPConn) SetWriteDeadline(t time.Time) error
设置写入/读取一个连接的超时时间。
func (c *TCPConn) SetKeepAlive(keepalive bool) os.Error
设置keepAlive属性,是操作系统层在TCP上没有数据和ACK的时候,会间隔性地发送keepalive包,操作系统可以通过该包来判断一个TCP连接是否已经断开,在Windows上默认2小时没有收到数据和keepalive包的时候人为断开TCP连接,这个功能和通常在应用层加的心跳包的功能类似。
其他的一些函数可以查看net
包。
网友评论