前期准备
- 需要
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]
copy
- package main
- import(
- "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:= <- messages
- fmt.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 string
- username := 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])
- }
- }