zoukankan      html  css  js  c++  java
  • 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
      
      "))
        _, 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 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])
    	}
    	
    	
    }


  • 相关阅读:
    OpenDiscussion_DataDrivenDesign
    WPF Auto LogOff
    Visual Studio模板
    我的TDD实践---UnitTest单元测试
    我的TDD实践---TDD概念篇
    我的TDD实践---SVN架设篇
    我的TDD实践---CI持续集成
    CSharpThinking---C#版本总结(附加三)
    CsharpThinking---代码契约CodeContract(八)
    c++文件偏移
  • 原文地址:https://www.cnblogs.com/keanuyaoo/p/3327627.html
Copyright © 2011-2022 走看看