Go Socket 编程

 

介绍

Socket 起源于 Unix,基于 Unix 的一切皆文件的哲学,万物都可以用 open -> read/write -> close 模式来操作。

Go 语言支持的 IP 类型。

Go 语言的 net 包中定义了很多类型、函数和方法用于网络编程,其中 IP 的定义如下:

type IP []byte

net 包中有很多函数来操作 IP,其中 ParseIP(string) IP 会把一个 IPv4 或者 IPv6 的地址转化成 IP 类型。

package main

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

func main() {

	if len(os.Args) != 2 {
		fmt.Fprintf(os.Stderr, "Usage: %s ipaddr\n", os.Args[0])
		os.Exit(1)
	}

	name := os.Args[1]
	addr := net.ParseIP(name)

	if addr == nil {
		fmt.Println("Invalid address")
	} else {
		fmt.Println("The address is", addr.String())
	}
}

TCP Socket

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)

TCPConn 可以在客户端和服务器端来读写数据。

我们需要有一个 TCPAddr 类型,它表示一个 TCP 的地址信息,定义如下:

type TCPAddr struct {
  IP IP
  Port int
}

在 Go 语言中通过 ResolveTCPAddr 获取一个 TCPAddr .


// net 参数是 tcp4 , tcp6 , tcp 中的任意一个。
// addr 表示域名或者地址 www.google.com:80 || 127.0.0.1:22 .
func ResolvTCPAddr(net, addr string) (*TCPAddr, os.Error)


TCP client

Go 语言通过 net 包中的 DialTCP 函数来建立一个 TCP 连接,并返回一个 TCPConn 类型的对象,当连接建立时服务器端也创建一个同类型的对象,此时客户端和服务器端通过各自拥有的 TCPConn 对象来进行数据交换。

一般情况下,客户但通过 TCPConn 将请求发送到服务器,服务器读取并解析来自客户但的请求,并返回迎丹信息,这个连接只有当任意一端关闭了连接之后才失效,不然这连接可以一直使用。

// net 参数是 tcp4 , tcp6 , tcp 中的任意一个。
// laddr 表示本机地址,一般设置为 nil
// raddr 表示远程服务器的地址
func DialTCP(net string, laddr, rddr *TCPAddr) (c *TCPConn, err os.ERror)

一个例子:

package main

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

func main() {
	asClientConnToWebServer()
}

func checkError(err error) {
	if err != nil {
		panic(err)
	}
}

func asClientConnToWebServer() {

	service := "www.chaos.luxe:80"
	tcpAddr, err := net.ResolveTCPAddr("tcp4", service)
	checkError(err)

	conn, err := net.DialTCP("tcp4", nil, tcpAddr)
	checkError(err)
	defer conn.Close()

	_, err = conn.Write([]byte("HEAD / HTTP/1.0\r\n"))
	checkError(err)

	result, err := ioutil.ReadAll(conn)
	checkError(err)

	resultString := *(*string)(unsafe.Pointer(&result))

	fmt.Println(resultString)

}

TCP Server

服务器端我们需要绑定服务到指定的非激活端口,并监听此端口。


func ListenTCP(net string, ladder *TCPAddr) (l *TCPListener, err os.Error)

func (l *TCPListener) Accept() (c Conn, err os.Error)

一个例子:

package main

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

func checkError(err error) {
	if err != nil {
		panic(err)
	}
}

func RunAsServer() {

	addr := "localhost:9091"
	tcpAddr, err := net.ResolveTCPAddr("tcp4", addr)
	checkError(err)

	tcpListener, err := net.ListenTCP("tcp4", tcpAddr)
	checkError(err)
	defer tcpListener.Close()

	for {
		conn, err := tcpListener.Accept()
		if err != nil {
			fmt.Errorf("Accept error %v\n", err)
			continue
		}
		go handleClient(conn)

	}
}

func handleClient(conn net.Conn) {
	defer conn.Close()

	for {
		daytime := time.Now().String()
		// don't care about return value
		conn.Write([]byte(daytime))
		//conn.Close()

		conn.R

		result, err := ioutil.ReadAll(conn)

		if err != nil {
			fmt.Errorf("ReadAll error %v\n", err)
			continue
		}
		resultString := *(*string)(unsafe.Pointer(&result))
		fmt.Printf("receive => %s\n", resultString)
	}

}
func main() {
	//asClientConnToWebServer()
	RunAsServer()
}

控制 TCP 连接

// 设置超时时间,客户端和服务器端都适用
func (c *TCPConn) SetTimeout(nesc int64) os.Error

// 设置客户端是否和服务器端一直保持连接。
func (c *TCPConn) SetKeepAlive(keepalive bool) os.Error

EOF


Power by TeXt.