前期准备


  • 需要​​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​​退出聊天
  • 只使用一套代码,通过命令行参数启动服务器还是客户端


实现:

[cpp]

​ view plain​

​ copy​


  1. package main

  2. import(
  3. "fmt"
  4. "os"
  5. "net"
  6. )


  7. //
  8. //错误检查
  9. //

  10. func checkError(err error,info string) (res bool) {

  11. if(err != nil){
  12. fmt.Println(info+"  " + err.Error())
  13. return false
  14. }
  15. return true
  16. }


  17. //
  18. //服务器端接收数据线程
  19. //参数:
  20. //      数据连接 conn
  21. //      通讯通道 messages
  22. //

  23. func Handler(conn net.Conn,messages chan string){

  24. fmt.Println("connection is connected from ...",conn.RemoteAddr().String())

  25. buf := make([]byte,1024)
  26. for{
  27. lenght, err := conn.Read(buf)
  28. if(checkError(err,"Connection")==false){
  29. conn.Close()
  30. break
  31. }
  32. if lenght > 0{
  33. buf[lenght]=0
  34. }
  35. //fmt.Println("Rec[",conn.RemoteAddr().String(),"] Say :" ,string(buf[0:lenght]))
  36. reciveStr :=string(buf[0:lenght])
  37. messages <- reciveStr

  38. }

  39. }


  40. //
  41. //服务器发送数据的线程
  42. //
  43. //参数
  44. //      连接字典 conns
  45. //      数据通道 messages
  46. //

  47. func echoHandler(conns *map[string]net.Conn,messages chan string){


  48. for{
  49. msg:= <- messages
  50. fmt.Println(msg)

  51. for key,value := range *conns {

  52. fmt.Println("connection is connected from ...",key)
  53. _,err :=value.Write([]byte(msg))
  54. if(err != nil){
  55. fmt.Println(err.Error())
  56. delete(*conns,key)
  57. }

  58. }
  59. }

  60. }



  61. //
  62. //启动服务器
  63. //参数
  64. //  端口 port
  65. //

  66. func StartServer(port string){
  67. service:=":"+port //strconv.Itoa(port);
  68. tcpAddr, err := net.ResolveTCPAddr("tcp4", service)
  69. checkError(err,"ResolveTCPAddr")
  70. l,err := net.ListenTCP("tcp",tcpAddr)
  71. checkError(err,"ListenTCP")
  72. conns:=make(map[string]net.Conn)
  73. messages := make(chan string,10)
  74. //启动服务器广播线程
  75. go echoHandler(&conns,messages)

  76. for  {
  77. fmt.Println("Listening ...")
  78. conn,err := l.Accept()
  79. checkError(err,"Accept")
  80. fmt.Println("Accepting ...")
  81. conns[conn.RemoteAddr().String()]=conn
  82. //启动一个新线程
  83. go Handler(conn,messages)

  84. }

  85. }



  86. //
  87. //客户端发送线程
  88. //参数
  89. //      发送连接 conn
  90. //

  91. func chatSend(conn net.Conn){

  92. var input string
  93. username := conn.LocalAddr().String()
  94. for {

  95. fmt.Scanln(&input)
  96. if input == "/quit"{
  97. fmt.Println("ByeBye..")
  98. conn.Close()
  99. os.Exit(0);
  100. }


  101. lens,err :=conn.Write([]byte(username + " Say :::" + input))
  102. fmt.Println(lens)
  103. if(err != nil){
  104. fmt.Println(err.Error())
  105. conn.Close()
  106. break
  107. }

  108. }

  109. }


  110. //
  111. //客户端启动函数
  112. //参数
  113. //      远程ip地址和端口 tcpaddr
  114. //

  115. func StartClient(tcpaddr string){

  116. tcpAddr, err := net.ResolveTCPAddr("tcp4", tcpaddr)
  117. checkError(err,"ResolveTCPAddr")
  118. conn, err := net.DialTCP("tcp", nil, tcpAddr)
  119. checkError(err,"DialTCP")
  120. //启动客户端发送线程
  121. go chatSend(conn)

  122. //开始客户端轮训
  123. buf := make([]byte,1024)
  124. for{

  125. lenght, err := conn.Read(buf)
  126. if(checkError(err,"Connection")==false){
  127. conn.Close()
  128. fmt.Println("Server is dead ...ByeBye")
  129. os.Exit(0)
  130. }
  131. fmt.Println(string(buf[0:lenght]))

  132. }
  133. }



  134. //
  135. //主程序
  136. //
  137. //参数说明:
  138. //  启动服务器端:  Chat server [port]             eg: Chat server 9090
  139. //  启动客户端:    Chat client [Server Ip Addr]:[Server Port]    eg: Chat client 192.168.0.74:9090
  140. //

  141. func main(){


  142. if len(os.Args)!=3  {
  143. fmt.Println("Wrong pare")
  144. os.Exit(0)
  145. }

  146. if os.Args[1]=="server" && len(os.Args)==3 {

  147. StartServer(os.Args[2])
  148. }


  149. if os.Args[1]=="client" && len(os.Args)==3 {

  150. StartClient(os.Args[2])
  151. }


  152. }