Go語言實現的簡單TCP服務及使用MySql


轉自:http://www.sharejs.com/codes/go/5997

http://www.sharejs.com/codes/go/4363

1、GO語言實現的簡單TCP服務代碼

package main
 
import (
"net"
"fmt"
)
 
var (
maxRead = 1100 msgStop = []byte("cmdStop") msgStart = []byte("cmdContinue") )
func main() { hostAndPort :
= "localhost:54321" listener := initServer(hostAndPort) for { conn, err := listener.Accept() checkError(err, "Accept: ") go connectionHandler(conn) } } func initServer(hostAndPort string) *net.TCPListener { serverAddr, err := net.ResolveTCPAddr("tcp", hostAndPort) checkError(err, "Resolving address:port failed: '" + hostAndPort + "'") listener, err := net.ListenTCP("tcp", serverAddr) checkError(err, "ListenTCP: ") println("Listening to: ", listener.Addr().String()) return listener } func connectionHandler(conn net.Conn) { connFrom := conn.RemoteAddr().String() println("Connection from: ", connFrom) talktoclients(conn) for { var ibuf []byte = make([]byte, maxRead + 1) length, err := conn.Read(ibuf[0:maxRead]) ibuf[maxRead] = 0 // to prevent overflow   switch err {     case nil:      handleMsg(length, err, ibuf)     default:      goto DISCONNECT   } } DISCONNECT: err := conn.Close() println("Closed connection:" , connFrom) checkError(err, "Close:" ) } func talktoclients(to net.Conn) { wrote, err := to.Write(msgStart) checkError(err, "Write: wrote " + string(wrote) + " bytes.") } func handleMsg(length int, err error, msg []byte) { if length > 0 { for i := 0; ; i++ { if msg[i] == 0 { break } } fmt.Printf("Received data: %v", string(msg[0:length])) fmt.Println(" length:",length) } } func checkError(error error, info string) { if error != nil {     panic("ERROR: " + info + " " + error.Error()) // terminate program   } }

例2 、

下面先創建一個簡單的Server端:

 

package main

import (
    "net"
    "fmt"
)

func main() {
    if ln, err := net.Listen("tcp", ":8080"); err == nil {
        defer ln.Close()
        for{
            ln.Accept()
            fmt.Println("Receive a Message")
        }
    }   
}

 

和腳本一樣簡單的寫法。

 

net.Listen(), 第一個參數是協議,tcp還是udp,第二個參數是ip地址,這里可以不填寫IP只填寫端口就是

 

使用defer Close,將close寫在listen之后是個好習慣

 

然后再循環中使用Accept()接受消息

 

 

下面是一個可以進行壓力測試的客戶端程序

 

package main

import (
    "net"
    "fmt"
)

func main() {
    currency := 20 //並發數,記住,一個連接數是打開一個端口號,window和linux的端口號都是有限制的
    count := 10 //每條連接發送多少次連接

    for i:=0;i<currency;i++ {
        go func(){
            for j:=0;j<count;j++ {
                sendMessage()
            }
        }()
    }
    select{}
}

func sendMessage() {
    conn, err := net.Dial("tcp", "127.0.0.1:8080")

    if(err != nil) {
        panic("error")
    }

    header := "GET / HTTP/1.0\r\n\r\n"
    fmt.Fprintf(conn, header)
}

 

 

2、Go語言中使用MySql

首先安裝mysql的go語言驅動

go get github.com/ziutek/mymysql/godrv

演示代碼

package users
  
import (
    "database/sql"
    "fmt"
    _ "github.com/ziutek/mymysql/godrv"
)
  
const (
    DB_NAME = "mysql_database_name"
    DB_USER = "mysql_user"
    DB_PASS = "mysql_password"
)
  
type User struct {
    Id      int    `json:"id"`
    Name string `json:"name"`
    Alias   string `json:"alias"`
}
  
func OpenDB() *sql.DB {
    db, err := sql.Open("mymysql", fmt.Sprintf("%s/%s/%s", DB_NAME, DB_USER, DB_PASS))
    if err != nil {
        panic(err)
    }
    return db
}
  
func UserById(id int) User {
    db := OpenDB()
    defer db.Close()
    row := db.QueryRow("SELECT `id`, `name`,`alias` FROM `users` WHERE id=?", id)
    user := new(User)
    row.Scan(&user.Id, &user.Name, &user.Alias)
    return user
}

例2:

go的sql包是在pkg/database中,里面的兩個包sqlsql/driver可以一起看。建議看這個兩個包之前可以先看看sql文件夾下的doc.txt。這個文檔說了幾點比較重要的:

1 這兩個包是真正Go風格的包。

2 這使用這兩個包就不需要關於並發處理了,也不需要維護自己的數據庫連接池了,一旦建立了一個連接,這個連接是可以在各個goroutine之間共用的。

sql/driver提供的是數據庫的接口,具體的實現還需要自己實現。

一、先看database/driver包

第一個用到的方法是Register

這個方法將實現了driver.Driver的驅動注冊到變量drivers中,當寫完一個驅動之后,就需要將驅動注冊到sql中才能使用sql包中的這些接口。這個實現了driver.Driver的必須實現了Open方法.

driver.Open返回的是driver.Conn,它的三個方法

Prepare : 參數綁定

Close : 關閉連接

Begin : 支持事務

先看Prepare,這個和php mysql pdo一樣的用法

Conn.Prepare("select * from test where a=?")

返回的Stmt結構:

Close : 關閉這個statement

NumInput : 返回有多少個可以綁定的參數

Exec : Insert或者update等無返回的使用

Query :select等查詢操作使用

Exec是綁定變量,然后返回Result結構

Query是綁定變量,然后返回Rows結果集

看Result里面的方法:

LastInsertId()  : Insert操作之后獲取到的主鍵id

RowsAffect() : 影響到的行數

Rows:

Columns() : 返回的數據有哪些列,其實就是返回的表列名

Close() : 關閉Rows,調用之后不能再進行任何操作

Next() : 將下一行的數據取到des[] Value中。這里的Value接口可以是int64,float64,bool,[]byte,string,time.Time

下面回到Begin,返回了Tx

開始事務之后除了查詢之外,就兩種行為:Commit和Rollback,這兩種行為都是Tx接口的方法

drvier中的結構全是接口性質的,它需要你來實現並注冊到Register中。

二、驅動的具體使用是在database/sql中

首先將幾個sql的結構看一遍

首先sql中的結構都是對driver中的結構進行了一層封裝,比如像Rows,有個內部屬性是rowsi driver.Rows。

對sql的實際操作都是使用driver.Rows里面的接口進行操作的,實際也就是使用你自己實現的driver進行操作。

driver和sql就像插頭和一個充滿插頭的汽車一樣,你實現了driver,即實現了這些插頭的配置,你就可使用sql這個汽車了。

Result : 和driver中的Result一致,即你如果實現了driver.Result,那你自然就實現了sql.Result。它是個接口,其實沒有什么特殊的用處,如果sql包中的所有Result都換成driver.Result也是行的,估計是作者希望返回值不要引用到其他包去,就使用這種方法。

Rows :  基於了driver.Rows, 還在上面擴展了幾個其他的方法。擁有方法:

Close

Cloumns

Err

Next

Scan

Stmt :基於driver.Stmt。擁有方法

Close

Exec

Query

QueryRow

Tx:基於driver.Tx。擁有方法:

Commit

Exec

Prepare

Query

QueryRow

Rollback

Stmt

從sql.Open開始

返回了sql.DB結構,這個結構是實現了driver.Conn結構,除了Conn已有的Prepare,Begin,Close之外,還直接多了幾個查詢方法:

Driver() : 返回當前驅動

Exec() : 直接進行操作

Query() : 進行查詢,返回Rows

QueryRow() : 預期返回單行,返回Row

不管Rows還是Row都有個很好用的方法Scan來將數據放到制定的變量中去。

比如下面就是典型的Rows用法

rows, err := db.Query("SELECT ...")
...
 
for rows.Next() {
    var id int
    var name string
     
    err = rows.Scan(&id, &name)
    ...
}

Prepare返回Stmt結構

Exec返回Result結構

至於這幾個結構也有各自的方法。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM