go语言渐入佳境-网络[5]-tcpaddr

TCPAddr

type TCPAddr struct {
IP IP
Port int
}

ResolveTCPAddr函数用于创建TCPAddr

1
func ResolveTCPAddr(net, addr string) (*TCPAddr, os.Error)

其中参数net是“tcp”,“tcp4”或“tcp6”之一,addr是由主机名或IP地址组成的字符串,后跟“:”后面的端口号,例如“www.google.com:80“或”127.0.0.1:22“。

1
2
3
4
5
6
7
8
func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err os.Error)

func (c *TCPConn) SetTimeout(nsec int64) os.Error
即使客户端无需发送任何内容,客户端也可能希望保持与服务器的连接。它可以使用:
func (c *TCPConn) SetKeepAlive(keepalive bool) os.Error

func (c *TCPConn) Write(b []byte) (n int, err os.Error)
func (c *TCPConn) Read(b []byte) (n int, err os.Error)

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/* GetHeadInfo
*/
package main

import (
"net"
"os"
"fmt"
"io/ioutil"
)

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]

// 生成TCPAddr
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, "Fatal error: %s", err.Error())
os.Exit(1)
}
}

测试

1
2
3
4
5
6
7
$ ./net www.baidu.com:80
HTTP/1.0 302 Found
Content-Length: 17931
Content-Type: text/html
Date: Fri, 18 Jan 2019 15:33:50 GMT
Etag: "54d9748e-460b"
Server: bfe/1.0.8.18

服务器

1
2
func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err os.Error)
func (l *TCPListener) Accept() (c Conn, err os.Error)

ListenTCP为服务器监听端口,Accept代表锁住,等待客户端连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/* DaytimeServer
*/
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
}

daytime := time.Now().String()
conn.Write([]byte(daytime)) // don't care about return value
conn.Close() // 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)
}
}

多线程服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/* ThreadedEchoServer
*/
package main

import (
"net"
"os"
"fmt"
)

func main() {

service := ":1201"
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
}
// run as a goroutine
go handleClient(conn)
}
}

func handleClient(conn net.Conn) {
// close connection on exit
defer conn.Close()

var buf [512]byte
for {
// read upto 512 bytes
n, err := conn.Read(buf[0:])
if err != nil {
return
}

// write the n bytes read
_, err2 := conn.Write(buf[0:n])
if err2 != nil {
return
}
}
}

func checkError(err error) {
if err != nil {
fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
os.Exit(1)
}
}