func ListenTCP(network string, laddr *TCPAddr) (*TCPListener, error)
func (l *TCPListener) Accept() (Conn, error)
package main
import ("fmt"
"net"
"os"
"time")
func main() {
service := ":1200"tcpAddr, err := net.ResolveTCPAddr("tcp4", service)
checkError(err)
listener, err := net.ListenTCP("tcp", tcpAddr)
checkError(err)for{
conn, err :=listener.Accept()if err !=nil {continue}
go handleClient(conn)
}
}
func handleClient(conn net.Conn) {
defer conn.Close()
daytime :=time.Now().String()
conn.Write([]byte(daytime)) //don't care about return value//we're finished with this client
}
func checkError(err error) {if err !=nil {
fmt.Fprintf(os.Stderr,"Fatal error: %s", err.Error())
os.Exit(1)
}
}
通过把业务处理分离到函数handleClient,我们就可以进一步地实现多并发执行了。看上去是不是很帅,增加go关键词就实现了服务端的多并发,从这个小例子也可以看出goroutine的强大之处。
控制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连接已经断开,这个功能和我们通常在应用层加的心跳包的功能类似。
UDP Socket
Go语言包中处理UDP Socket和TCP Socket不同的地方就是在服务器端处理多个客户端请求数据包的方式不同,UDP缺少了对客户端连接请求的Accept函数。其他基本几乎一模一样,只有TCP换成了UDP而已。UDP的几个主要函数如下所示:
func ResolveUDPAddr(net, addr string) (*UDPAddr, os.Error)
func DialUDP(net string, laddr, raddr *UDPAddr) (c *UDPConn, err os.Error)
func ListenUDP(net string, laddr *UDPAddr) (c *UDPConn, err os.Error)
func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err os.Error)
func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (n int, err os.Error)
udp客户端一个UDP的客户端代码如下所示,我们可以看到不同的就是TCP换成了UDP而已:
package main
import ("fmt"
"net"
"os")
func main() {if len(os.Args) != 2{
fmt.Fprintf(os.Stderr,"Usage: %s host:port", os.Args[0])
os.Exit(1)
}
service := os.Args[1]
udpAddr, err := net.ResolveUDPAddr("udp4", service)
checkError(err)
conn, err := net.DialUDP("udp", nil, udpAddr)
checkError(err)
_, err= conn.Write([]byte("anything"))
checkError(err)var buf [512]byten, err := conn.Read(buf[0:])
checkError(err)
fmt.Println(string(buf[0:n]))
os.Exit(0)
}
func checkError(err error) {if err !=nil {
fmt.Fprintf(os.Stderr,"Fatal error %s", err.Error())
os.Exit(1)
}
UDP服务端:
package main
import ("fmt"
"net"
"os"
"time")
func main() {
service := ":1200"udpAddr, err := net.ResolveUDPAddr("udp4", service)
checkError(err)
conn, err := net.ListenUDP("udp", udpAddr)
checkError(err)for{
handleClient(conn)
}
}
func handleClient(conn*net.UDPConn) {var buf [512]byte_, addr, err := conn.ReadFromUDP(buf[0:])if err !=nil {return}
daytime :=time.Now().String()
conn.WriteToUDP([]byte(daytime), addr)
}
func checkError(err error) {if err !=nil {
fmt.Fprintf(os.Stderr,"Fatal error %s", err.Error())
os.Exit(1)
}
}
通过对TCP和UDP Socket编程的描述和实现,可见Go已经完备地支持了Socket编程,而且使用起来相当的方便,Go提供了很多函数,通过这些函数可以很容易就编写出高性能的Socket应用。