您的位置:首页 > 理论基础 > 计算机网络

Go语言网络编程示例-客户端篇

2014-04-03 11:38 1006 查看
// occlient project main.go
package main

import (
"crypto/md5"
"encoding/hex"
"flag"
"log"
"os"
"runtime"
"time"
)

func MD5(b []byte) string {
h := md5.New()
h.Write(b)
x := h.Sum(nil)
y := make([]byte, 32)
hex.Encode(y, x)
return string(y)
}

var sleep time.Duration

func DateTime_YYYYMMDDHHMMSS() string {
return time.Now().Format("20060102150405")
}

func main() {
runtime.GOMAXPROCS(1000000)
addr := flag.String("addr", "127.0.0.1:5555", "message server address and port ,default 180.153.149.147:8443")
user := flag.Int("uid", 10000, "user login id,default 10000")
sec := flag.String("sec", "abc", "secrity key")
room := flag.Int("rid", 11111, "client type,default 11111")
c := flag.Int("c", 1, "concurrent number,default 1")
t := flag.Int("t", 1, "precent %t% second send a message ,default 1 s")
sleep = time.Duration(*t) * time.Second
flag.Parse()

for i := 1; i <= *c; i++ {
go doconnect(*addr, int32(*user)+int32(i), int32(*room), *sec)
}
select {}
os.Exit(0)
}

func doconnect(addr string, uid int32, room int32, key string) {
client := NewClient(addr, uid, room, key)
for {
ok := client.Handshake()
if ok {
ok = client.Join()
break
}
client.Logout()
log.Printf("Reconnect %+v", client)
}

//partten := "20060102150405"

for {
if client.IsLogin() {
client.SendMessage("Hello Openchat")
time.Sleep(sleep)
} else {
client.Logout()
doconnect(addr, uid, room, key)
}
}
//defer client.Logout()
//defer client.Logout()
}

func checkError(msg string, err error) {
if err != nil {
log.Println(msg, err)
}
}

// occlient
package main

import (
"bytes"
"encoding/binary"
"io"
"log"
"net"
"time"
)

type Client struct {
Address string
UserId int32
RoomId int32
SecKey string
sequence int32
logined bool
session net.Conn
nextInt func() int32
}

func NewClient(addr string, user int32, room int32, key string) *Client {
c := new(Client)
c.sequence = 0
c.Address = addr
c.UserId = user
c.RoomId = room
c.SecKey = key
c.logined = false
c.nextInt = intSeq()
return c
}

func intSeq() func() int32 {
var i int32 = 0
return func() int32 {
i += 1
return i
}
}

func (c *Client) IsLogin() bool {
return c.logined
}

func (c *Client) Logout() {
c.logined = false
if c.session != nil {
c.session.Close()
}
}

func readPacket(conn net.Conn) ([]byte, error) {
result := bytes.NewBuffer(nil)
tb := make([]byte, 4)
conn.SetReadDeadline(time.Now().Add(time.Second * 30))
i, err := io.ReadFull(conn, tb)
result.Write(tb[0:i])
if err != nil {
return result.Bytes(), err
}
var length int32
err = binary.Read(result, binary.BigEndian, &length)
if length > 4096 {
conn.Close()
log.Printf("Invalid Length %d", length)
return result.Bytes(), err
}
result = bytes.NewBuffer(nil)
result.Write(tb)
tb = make([]byte, length)
conn.SetReadDeadline(time.Now().Add(time.Second * 30))
i, err = io.ReadFull(conn, tb)
result.Write(tb)
return result.Bytes(), err

}

func (c *Client) Join() bool {
join := NewPacket(c.nextInt(), MESSAGE_JOIN)
join.AddTagInt32(TAG_CLIENTID, c.UserId)
join.AddTagInt32(TAG_ROOMID, c.RoomId)
b, err := join.Encode()
//log.Printf("Send Hex %x %s", b, join.String())
//conn.Write()
_, err = c.session.Write(b)
checkError("Join", err)
return err != nil
//b, err = readPacket(conn)
//checkError(err)
//if err != nil {
// return false
//}
//join.Decode(b)
//log.Printf("Recv Hex %x %s", b, join.String())
//return true
}

func (c *Client) Handshake() bool {
_, err := net.ResolveTCPAddr("tcp4", c.Address)
checkError("Handshake ResolveTCPAddr", err)
if err != nil {
return false
}
conn, err := net.DialTimeout("tcp", c.Address, time.Second*30) //net.DialTCP("tcp", nil, tcpAddr)
checkError("Handshake DialTimeout", err)
if err != nil {
return false
}
conn.(*net.TCPConn).SetKeepAlive(true)
conn.(*net.TCPConn).SetNoDelay(true)
c.session = conn
handshake := NewHandshake(c.SecKey)
b, err := handshake.Encode()
_, err = conn.Write(b)
//log.Printf("Send Hex %d %x %s", i, b, handshake.String())
checkError("Handshake Write", err)
b, err = readPacket(conn)
checkError("Handshake Read", err)
if err != nil {
return false
}
handshake.Decode(b)
//log.Printf("Recv Hex %x %s", b, handshake.String())
c.logined = true
go loop(conn)
return true
}

func (c *Client) SendMessage(text string) bool {
chat := NewPacket(c.nextInt(), MESSAGE_CHAT)
chat.AddTagInt32(TAG_FROM, c.UserId)
chat.AddTagInt32(TAG_TO, c.RoomId)
chat.AddTagString(TAG_CONTENT, text)
b, err := chat.Encode()
//log.Printf("Send Hex %x %s", b, chat.String())
_, err = c.session.Write(b)
checkError("SendMessage Write", err)
if err != nil {
c.logined = false
}
return err != nil
}

func loop(conn net.Conn) {
for {
//conn.SetReadDeadline(time.Now().Add(time.Second * 90))
b, err := readPacket(conn)
checkError("Loop readPacket", err)
if err != nil {
break
}
pk := new(Packet)
err = pk.Decode(b)
checkError("Loop Decode", err)
if err == nil {
//log.Printf("Receive Hex %x %s", b, pk.String())
} else {
log.Printf("Receive Hex %x", b)
}
}
log.Printf("Loop exit %+v/%+v", conn.LocalAddr(), conn.RemoteAddr())
}

// protocol
package main

import (
"bytes"
"encoding/binary"
"fmt"
"log"
"math/rand"
"strconv"
"time"
)

const (
TAG_CODE int32 = 0
TAG_CLIENTID int32 = 1
TAG_FROM int32 = 2
TAG_TO int32 = 3
TAG_ROOMID int32 = 4
TAG_CONTENT int32 = 5 //string
TAG_ICON int32 = 6 //string
)

const (
MESSAGE_JOIN int32 = 1
MESSAGE_LEAVE int32 = 2
MESSAGE_CHAT int32 = 3
MESSAGE_USERLIST int32 = 4
ACK_MESSAGE int32 = 0x0
KEEPALIVE_MESSAGE int32 = 111
ACK_KEEPALIVE_MESSAGE int32 = 0x1111
UNKNOWN_MESSAGE int32 = 0x7474
)

type PacketEncodeError struct {
Err string
}

func (e *PacketEncodeError) Error() string {
return e.Err
}

type Handshake struct {
PacketLength int32
Random int32
Timestamp int32
Version byte
Signature string //MD5(密钥+yyyymmddhhMMss+Random+Version)
}
type TLV struct {
Tag int32
Length int32
Value []byte
}

func NewTlv(tag int32, value string) *TLV {
tlv := new(TLV)
tlv.Tag = tag
tlv.Value = []byte(value)
tlv.Length = int32(len(tlv.Value))
return tlv
}

func NewTlv1(tag int32, value int32) *TLV {
tlv := new(TLV)
tlv.Tag = tag
buf := bytes.NewBuffer(nil)
binary.Write(buf, binary.BigEndian, &value)
tlv.Value = buf.Bytes()
tlv.Length = 4
return tlv
}

func (p *TLV) Encode() []byte {
buf := bytes.NewBuffer(nil)
binary.Write(buf, binary.BigEndian, p.Tag)
binary.Write(buf, binary.BigEndian, p.Length)
buf.Write(p.Value)
return buf.Bytes()
}

func (p *TLV) Decode(b []byte) error {
return nil
}

type Packet struct {
PacketLength int32
Sequence int32
Timestamp int32
MessageType int32
Tags []TLV
}

func NewPacket(seq int32, mtype int32) *Packet {
packet := new(Packet)
packet.Sequence = seq
packet.Timestamp = int32(time.Now().Unix())
packet.MessageType = mtype
packet.Tags = make([]TLV, 0)
return packet
}

func (p *Packet) Encode() ([]byte, error) {
buf := bytes.NewBuffer(nil)
err := binary.Write(buf, binary.BigEndian, p.Sequence)
err = binary.Write(buf, binary.BigEndian, p.Timestamp)
err = binary.Write(buf, binary.BigEndian, p.MessageType)
for i := 0; i < len(p.Tags); i++ {
tlv := p.Tags[i]
buf.Write(tlv.Encode())
}
b := buf.Bytes()
p.PacketLength = int32(len(b))
buf = bytes.NewBuffer(nil)
err = binary.Write(buf, binary.BigEndian, p.PacketLength)
buf.Write(b)
return buf.Bytes(), err
}

func (p *Packet) Decode(b []byte) error {
buf := bytes.NewBuffer(nil)
_, err := buf.Write(b)

err = binary.Read(buf, binary.BigEndian, &p.PacketLength)
if int32(len(b)) != p.PacketLength+4 {
log.Printf("Invaild PacketLength %d/%d", len(b), p.PacketLength)
buf = bytes.NewBuffer(nil)
_, err = buf.Write(b)
}
err = binary.Read(buf, binary.BigEndian, &p.Sequence)
err = binary.Read(buf, binary.BigEndian, &p.Timestamp)
err = binary.Read(buf, binary.BigEndian, &p.MessageType)
for len(buf.Bytes()) > 0 {
var t, l int32
binary.Read(buf, binary.BigEndian, &t)
binary.Read(buf, binary.BigEndian, &l)
if l > 4096 {
log.Printf("Invaild Tag Length %d/%d", t, l)
break
}
b := make([]byte, l)
buf.Read(b)
p.AddTag(TLV{t, l, b})
}
return err
}

func (p *Packet) AddTagString(tag int32, value string) {
tlv := TLV{Tag: tag, Value: []byte(value)}
tlv.Length = int32(len(tlv.Value))
p.Tags = append(p.Tags, tlv)
}

func (p *Packet) AddTagInt32(tag int32, value int32) {
tlv := TLV{Tag: tag, Length: 4}
buf := bytes.NewBuffer(nil)
binary.Write(buf, binary.BigEndian, &value)
tlv.Value = buf.Bytes()
p.Tags = append(p.Tags, tlv)
}

func (p *Packet) AddTag(tag TLV) {
p.Tags = append(p.Tags, tag)
}

func (p *Packet) String() string {
return fmt.Sprintf("Packet %+v", *p)
}

func NewHandshake(key string) *Handshake {
handshake := new(Handshake)
handshake.Random = rand.Int31()
handshake.Timestamp = int32(time.Now().Unix())
handshake.Version = 1
handshake.Signature = MD5([]byte(key + strconv.FormatInt(int64(handshake.Timestamp), 10) + strconv.FormatInt(int64(handshake.Random), 10) + strconv.Itoa(int(handshake.Version))))
//handshake.PacketLength = 4 + 4 + 1 + int32(len([]byte(handshake.Signature)))
return handshake
}

func (p *Handshake) Encode() ([]byte, error) {
buf := bytes.NewBuffer(nil)
b := []byte(p.Signature)
p.PacketLength = int32(len(b) + 9)
err := binary.Write(buf, binary.BigEndian, p.PacketLength)
err = binary.Write(buf, binary.BigEndian, p.Random)
err = binary.Write(buf, binary.BigEndian, p.Timestamp)
err = binary.Write(buf, binary.BigEndian, p.Version)
_, err = buf.Write(b)
return buf.Bytes(), err
}

func (p *Handshake) Decode(b []byte) error {
if len(b) >= 50 {
buf := bytes.NewBuffer(nil)
_, err := buf.Write(b)
err = binary.Read(buf, binary.BigEndian, &p.PacketLength)
err = binary.Read(buf, binary.BigEndian, &p.Random)
err = binary.Read(buf, binary.BigEndian, &p.Timestamp)
err = binary.Read(buf, binary.BigEndian, &p.Version)
p.Signature = string(buf.Bytes())
//p.PacketLength = int32(len(b))
return err
}
return &PacketEncodeError{"Invalid PakcetLength " + string(len(b))}
}

func (p *Handshake) String() string {
return fmt.Sprintf("Handshake %+v", *p)
}



转载地址:http://www.oschina.net/code/snippet_874_17443
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: