這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
前期準備
- 需要
import "net"
包
IP
類型,其中一個重要的方法是IP.ParseIP(ipaddr string)
來判斷是否是合法的IP地址
TCP Client
func (c *TCPConn) Write(b []byte) (n int, err os.Error)
用於發送資料,返回傳送的資料長度或者返回錯誤,是TCPConn
的方法
func (c *TCPConn) Read(b []byte) (n int, err os.Error)
用於接收資料,返回接收的長度或者返回錯誤,是TCPConn
的方法
TCPAddr
類型,儲存TCP的地址資訊,包括地址和連接埠
type TCPAddr struct { IP IP Port int }
func ResolveTCPAddr(net, addr string) (*TCPAddr, os.Error)
擷取一個TCPAddr
,參數都是string
類型,net是個const string
,包括tcp4
,tcp6
,tcp
一般使用tcp
,相容v4和v6,addr
表示ip地址,包括連接埠號碼,如www.google.com:80
之類的
func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err os.Error)
用來串連(connect)到遠程伺服器上,net表示協議方式,tcp
,tcp4
或者tcp6
,laddr
表示本機地址,一般為nil
,raddr
表示遠程地址,這裡的laddr
和raddr
都是TCPAddr
類型的,一般是上一個函數的傳回值。
作為一個TCP的用戶端,基本的操作流程如下:
service="www.google.com:80" tcpAddr, err := net.ResolveTCPAddr("tcp4", service) conn, err := net.DialTCP("tcp", nil, tcpAddr) _, err = conn.Write([]byte("HEAD / HTTP/1.0\r\n\r\n")) _, err = conn.Read(b) / result, err := ioutil.ReadAll(conn)
TCP Server
func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err os.Error)
用來監聽連接埠,net
表示協議類型,laddr
表示本機地址,是TCPAddr
類型,注意,此處的laddr包括連接埠,返回一個*TCPListener
類型或者錯誤
func (l *TCPListener) Accept() (c Conn, err os.Error)
用來返回一個新的串連,進行後續操作,這是TCPListener
的方法,一般TCPListener
從上一個函數返回得來。
伺服器的基本操作流程為:
service:=":9090" tcpAddr, err := net.ResolveTCPAddr("tcp4", service) l,err := net.ListenTCP("tcp",tcpAddr) conn,err := l.Accept() go Handler(conn) //此處使用go關鍵字建立線程處理串連,實現並發
一個例子
需求
實現一個公用聊天伺服器。
- 伺服器接收用戶端的資訊
- 接收完以後將用戶端的資訊發送到所有的用戶端上
- 用戶端使用
/quit
退出聊天
- 只使用一套代碼,通過命令列參數啟動伺服器還是用戶端
實現:
package mainimport("fmt""os""net")////////////////////////////////////////////////////////////錯誤檢查//////////////////////////////////////////////////////////func checkError(err error,info string) (res bool) {if(err != nil){fmt.Println(info+" " + err.Error())return false}return true}////////////////////////////////////////////////////////////伺服器端接收資料線程//參數://資料連線 conn//通訊通道 messages//////////////////////////////////////////////////////////func Handler(conn net.Conn,messages chan string){fmt.Println("connection is connected from ...",conn.RemoteAddr().String())buf := make([]byte,1024)for{lenght, err := conn.Read(buf)if(checkError(err,"Connection")==false){conn.Close()break}if lenght > 0{buf[lenght]=0}//fmt.Println("Rec[",conn.RemoteAddr().String(),"] Say :" ,string(buf[0:lenght]))reciveStr :=string(buf[0:lenght])messages <- reciveStr}}////////////////////////////////////////////////////////////伺服器發送資料的線程////參數//串連字典 conns//資料通道 messages//////////////////////////////////////////////////////////func echoHandler(conns *map[string]net.Conn,messages chan string){for{msg:= <- messagesfmt.Println(msg)for key,value := range *conns {fmt.Println("connection is connected from ...",key)_,err :=value.Write([]byte(msg))if(err != nil){fmt.Println(err.Error())delete(*conns,key)}}}}////////////////////////////////////////////////////////////啟動伺服器//參數//連接埠 port//////////////////////////////////////////////////////////func StartServer(port string){service:=":"+port //strconv.Itoa(port);tcpAddr, err := net.ResolveTCPAddr("tcp4", service)checkError(err,"ResolveTCPAddr")l,err := net.ListenTCP("tcp",tcpAddr)checkError(err,"ListenTCP")conns:=make(map[string]net.Conn)messages := make(chan string,10)//啟動伺服器廣播線程go echoHandler(&conns,messages)for {fmt.Println("Listening ...")conn,err := l.Accept()checkError(err,"Accept")fmt.Println("Accepting ...")conns[conn.RemoteAddr().String()]=conn//啟動一個新線程go Handler(conn,messages) }}////////////////////////////////////////////////////////////用戶端發送線程//參數//發送串連 conn//////////////////////////////////////////////////////////func chatSend(conn net.Conn){var input stringusername := conn.LocalAddr().String()for {fmt.Scanln(&input)if input == "/quit"{fmt.Println("ByeBye..")conn.Close()os.Exit(0);}lens,err :=conn.Write([]byte(username + " Say :::" + input))fmt.Println(lens)if(err != nil){fmt.Println(err.Error())conn.Close()break}}}////////////////////////////////////////////////////////////用戶端啟動函數//參數//遠程ip地址和連接埠 tcpaddr//////////////////////////////////////////////////////////func StartClient(tcpaddr string){tcpAddr, err := net.ResolveTCPAddr("tcp4", tcpaddr)checkError(err,"ResolveTCPAddr")conn, err := net.DialTCP("tcp", nil, tcpAddr)checkError(err,"DialTCP")//啟動用戶端發送線程go chatSend(conn)//開始用戶端輪訓buf := make([]byte,1024)for{lenght, err := conn.Read(buf)if(checkError(err,"Connection")==false){conn.Close()fmt.Println("Server is dead ...ByeBye")os.Exit(0)}fmt.Println(string(buf[0:lenght]))}}////////////////////////////////////////////////////////////主程式////參數說明://啟動伺服器端: Chat server [port]eg: Chat server 9090//啟動用戶端: Chat client [Server Ip Addr]:[Server Port] eg: Chat client 192.168.0.74:9090//////////////////////////////////////////////////////////func main(){if len(os.Args)!=3 {fmt.Println("Wrong pare")os.Exit(0)}if os.Args[1]=="server" && len(os.Args)==3 {StartServer(os.Args[2])}if os.Args[1]=="client" && len(os.Args)==3 {StartClient(os.Args[2])}}