Go语言简略的TCP编程

Go语言简单的TCP编程前期准备需要import net包IP类型,其中一个重要的方法是IP.ParseIP(ipaddr string)来

Go语言简单的TCP编程

前期准备
  • 需要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或者tcp6laddr表示本机地址,一般为nilraddr表示远程地址,这里的laddrraddr都是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])}}