1. 程式人生 > >go學習(8)TCP程式設計

go學習(8)TCP程式設計

go網路程式設計簡單易上手,tcp可以很容易實現一個客戶端一個執行緒(goroutine),業務處理清楚明瞭。

服務端:

package main

import (
	"fmt"
	"net"
)

const (
	MAX_MSG_LENGTH = 1024 //每次最大收多少資料
)

//處理玩家資料
func Echo(c net.Conn) {
	fmt.Printf("Client conn %s", c.RemoteAddr().String())
	data := make([]byte, MAX_MSG_LENGTH) //用於接收資料緩衝
	defer c.Close()                      //defer 關閉連線

	for { //迴圈處理客戶端資料
		data = []byte{}
		n, err := c.Read(data) //這裡阻塞等到客戶端資料到來
		if err != nil {
			fmt.Printf("Read message failed:%s\n", err.Error())
			return
		}

		if n > 0 {
			c.Write(data) //將客戶端的資料傳送回去
		}
	}
}

func main() {
	fmt.Printf("Server is ready...\n")
	l, err := net.Listen("tcp", ":7777") //繫結協議,埠
	if err != nil {
		fmt.Printf("Failure to listen:%s\n", err.Error())
		return
	}

	for {
		if c, err := l.Accept(); err == nil { //接受連線
			go Echo(c) //每一個Client啟動一個協程,處理資料
		}
	}
}

 

客戶端:

package main

import (
	"bufio"
	"fmt"
	"net"
	"os"
	"time"
)

//客戶端類
type Client struct {
	conn1   net.Conn //連線
	isAlive bool     //是否活躍
	sendStr chan string
	recvStr chan string
}

//客戶端的連線函式
func (c *Client) Connect() bool {
	if c.isAlive { //已經連線成功
		return true
	} else {
		var err error
		c.conn1, err = net.Dial("tcp", "127.0.0.1:7777") //連線服務端

		if err != nil {
			fmt.Printf("Failure to connect:%s\n", err.Error())
			return false
		}

		c.isAlive = true
	}

	return true
}

//傳送資料介面
func (c *Client) Echo() {
	line := <-c.sendStr         //line為要傳送的資料(從傳送管道取資料)
	c.conn1.Write([]byte(line)) //轉為byte[]傳送

	buf := make([]byte, 1024)
	n, err := c.conn1.Read(buf) //等待服務端返回資料
	if err != nil {
		c.recvStr <- string("Server close...")
		c.conn1.Close()
		c.isAlive = false
		return
	}

	time.Sleep(1 * time.Second)
	c.recvStr <- string(buf[0:n]) //收到的資料寫入管道recvStr
}

func Work(tc *Client) {
	if !tc.isAlive {
		if tc.Connect() {
			tc.Echo()
		} else {
			<-tc.sendStr
			tc.recvStr <- string("Server close...")
		}
	} else {
		tc.Echo()
	}
}

func main() {
	var tc Client                  //客戶端例項
	tc.sendStr = make(chan string) //建立傳送、接收管道
	tc.recvStr = make(chan string)

	if !tc.Connect() {
		return
	}

	r := bufio.NewReader(os.Stdin) //從命令列接收資料
	for {
		switch line, ok := r.ReadString('\n'); true { //讀到換行線束
		case ok != nil:
			fmt.Printf("bye bye!\n")
			return
		default:
			go Work(&tc)
			tc.sendStr <- line
			s := <-tc.recvStr //等待接收到資料,這裡會阻塞到有資料為止
			fmt.Printf("recv:%s\n", s)
		}
	}
}