用Go写一个简单的TCP server or client 模型

对Conn封装的基本思路

go内置了net包已经很好的封装了socket通讯。然而在实际使用中,由于net/Conn的Read/Write方法是堵塞的原因,必须将其放入单独的goroutine中进行处理。

我们先简单的整理下思路,对于连接(Conn)的处理,我们可以开启2条goroutine进行处理,一条用于堵塞的Read的处理,另一条进行Write的处理。

这里必须指出,其实Write本身就是线程安全的,也就是我们在别的任何地方都可以进行Write,但是Write是堵塞的,所以考虑到这点,我们还是将其放入一个单独的goroutine中进行处理。

这样设计的原因在于Conn是支持同时Read/Write的,这样我们的基本的Conn的模型就成型了。对于服务端或者客户端而言,我们只需要封装对应过来的Conn即可,Conn的读写goroutine进行处理,并将获得的事件抛向外部。

那么我们就按这个思路来实现一个简单的Connection封装,该封装支持线程安全的写,并且支持解包操作。

package tcpnetwork

import (
    "errors"
    "log"
    "net"
    "time"
)

const (
    kConnStatus_None = iota
    kConnStatus_Connected
    kConnStatus_Disconnected
)

const (
    kConnEvent_None = iota
    kConnEvent_Connected
    kConnEvent_Disconnected
    kConnEvent_Data
    kConnEvent_Close
)

const (
    kConnConf_DefaultSendTimeoutSec = 5
    kConnConf_MaxReadBufferLength   = 0xffff // 0xffff
)

type Connection struct {
    conn                net.Conn
    status              int
    connId              int
    sendMsgQueue        chan []byte
    sendTimeoutSec      int
    eventQueue          IEventQueue
    streamProtocol      IStreamProtocol
    maxReadBufferLength int
    userdata            interface{}
    from                int
    readTimeoutSec      int
}

func newConnection(c net.Conn, sendBufferSize int, eq IEventQueue) *Connection {
    return &Connection{
        conn:                c,
        status:              kConnStatus_None,
        connId:              0,
        sendMsgQueue:        make(chan []byte, sendBufferSize),
        sendTimeoutSec:      kConnConf_DefaultSendTimeoutSec,
        maxReadBufferLength: kConnConf_MaxReadBufferLength,
        eventQueue:          eq,
    }
}

type ConnEvent struct {
    EventType int
    Conn      *Connection
    Data      []byte
}

func newConnEvent(et int, c *Connection, d []byte) *ConnEvent {
    return &ConnEvent{
        EventType: et,
        Conn:      c,
        Data:      d,
    }
}

//  directly close, packages in queue will not be sent
func (this *Connection) close() {
    if kConnStatus_Connected != this.status {
        return
    }

    this.conn.Close()
    this.status = kConnStatus_Disconnected
}

func (this *Connection) Close() {
    if this.status != kConnStatus_Connected {
        return
    }

    select {
    case this.sendMsgQueue <- nil:
        {
            //  nothing
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值