하나의 TCP 장거리 연결 장치 관리 백그라운드 프로젝트(8)

7579 단어 golangpostgresqltcp

전편


하나의 TCP 장거리 연결 장치 관리 백그라운드 프로젝트(一) 하나의 TCP 장거리 연결 장치 관리 백그라운드 프로젝트(二) 하나의 TCP 장거리 연결 장치 관리 백그라운드 프로젝트(3) 하나의 TCP 장거리 연결 장치 관리 백그라운드 프로젝트(4) 하나의 TCP 장거리 연결 장치 관리 백그라운드 프로젝트(5) 하나의 TCP 장거리 연결 장치 관리 백그라운드 프로젝트(6) 하나의 TCP 장거리 연결 장치 관리 백그라운드 프로젝트(7)
Github 저장소 주소

TCP 서버


앞의 모든 내용은 jtt808 프로토콜을 바탕으로 하는 TCP 서버를 실현하기 위한 작업입니다. 저희가 지금 필요로 하는 것은 위에서 설명한 내용을 통합하여 각 모듈이 업무를 조율하고 전체적인 서비스 절차를 완성하도록 하는 것입니다.

로딩 구성


먼저 프로필 불러오기를 말해 보세요. 한 응용 프로그램에 대해 유연성을 높이기 위해서는 프로필을 사용해야 합니다.종합적으로 고려하여 저는 toml 형식의 프로필을 사용하고 해석 라이브러리는 "github.com/BurntSushi/toml"를 사용합니다
# config

[tcp]
ip = ""
port = 19903

[web]
ip = ""
port = 8080

[map]
appKey = "your baidu map key"

[postgresql]
hostname="localhost"
tablename="pqgodb"
user="pqgotest"
password="pqgotest"

구성에는 구성에 적합한 구조체를 정의하는 전체 적용 구성이 포함됩니다.
type Config struct {
    TcpCfg TcpConfig `toml:"tcp"`
    WebCfg WebConfig `toml:"web"`
    MapCfg MapConfig `toml:"map"`
    PgCfg  PgConfig  `toml:"postgresql"`
}

type TcpConfig struct {
    Ip   string
    Port int
}

type WebConfig struct {
    Ip   string
    Port int
}

type MapConfig struct {
    AppKey string
}

type PgConfig struct {
    Hostname  string
    Tablename string
    User      string
    Password  string
}

var config Config

로딩 구성
curpath := GetCurrentDirectory()
_, err = toml.DecodeFile(curpath+"/config.toml", &config)
if err != nil {
    log.Info("config error: ", err)
    return
}

여기서 GetCurrentDirectory는 현재 적용되는 절대 경로를 가져옵니다.
func GetCurrentDirectory() string {
    dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
    if err != nil {
        log.Fatal(err)
        return ""
    }
    return strings.Replace(dir, "\\", "/", -1) // \ /
}

TCP 연결 관리


이 부분은 기본적으로 앞의 백엔드 모델의 설명과 일치한다.
var connManger map[string]*term.Terminal

connManger = make(map[string]*term.Terminal)

서버를 만들까,listen과accept를 만들까
address := config.TcpCfg.Ip + ":" + strconv.FormatInt(int64(config.TcpCfg.Port), 10)
log.Info("address port ", address)

listenSock, err := net.Listen("tcp", address)
if err != nil {
    log.WithFields(logrus.Fields{"Error:": err.Error()}).Error("check")
    os.Exit(1)
}

defer listenSock.Close()

for {
    newConn, err := listenSock.Accept()
    if err != nil {
        continue
    }

    go recvConnMsg(newConn)
}

recvConnMsg 처리 TCP 클라이언트 데이터 수신
func recvConnMsg(conn net.Conn){
    
}

먼저 터미널을 만들고 connManager에 추가합니다.
buf := make([]byte, 0)
addr := conn.RemoteAddr()
log.WithFields(logrus.Fields{"network": addr.Network(), "ip": addr.String()}).Info("recv")

var t *term.Terminal = &term.Terminal{
    Conn:   conn,
    Engine: engine,
    Ch:     make(chan int),
}
connManger[addr.String()] = t
ipaddress = addr.String()

TCP가 분리되면 connManager에서 해당 요소를 제거해야 합니다.
defer func() {
    delete(connManger, addr.String())
    conn.Close()
}()

그 다음은 데이터를 반복해서 읽고 처리하는 것이다.
for {
    tempbuf := make([]byte, 1024)
}

데이터를 읽습니다. 이 데이터는 지난번에 처리되지 않은 데이터와 결합해야 합니다. 왜냐하면 패키지 해체가 있을 수 있기 때문입니다.
n, err := conn.Read(tempbuf)

if err != nil {
    log.WithFields(logrus.Fields{"network": addr.Network(), "ip": addr.String()}).Info("closed")
    return
}

buf = append(buf, tempbuf[:n]...)
var outlog string
for _, val := range buf {
    outlog += fmt.Sprintf("%02X", val)
}
log.WithFields(logrus.Fields{"data": outlog}).Info("

필터를 호출하여 수신된 데이터를 처리하고 이미 사용된 바이트를 오프셋합니다.
var msg []proto.Message
var lens int
msg, lens, err = proto.Filter(buf)
if err != nil {
    //
}

buf = buf[lens:]

msg는 메시지 슬라이스로 이 슬라이스에 있는 메시지를 순환 처리합니다. 모두 처리될 때까지:
for len(msg) > 0 {
    // 
    sendBuf := t.Handler(msg[0])

    if sendBuf != nil {
        outlog = ""
        for _, val := range sendBuf {
            outlog += fmt.Sprintf("%02X", val)
        }
        log.WithFields(logrus.Fields{"data": outlog}).Info("---> ")

        logframe := &LogFrame{
            Stamp: time.Now(),
            Dir:   1,
            Frame: outlog,
        }
        _, err = engine.Insert(logframe)
        if err != nil {
            log.WithFields(logrus.Fields{"error": err.Error()}).Info("insert")
        }

        conn.Write(sendBuf)

        msg = msg[1:]
    }
}

메시지 처리는 프로세서를 호출합니다. 프로세서는 응답해야 할 데이터를 되돌려줍니다. 프로세서가 되돌려주는 데이터를 conn. Write를 통해 대응하는 tcp에 보내면 응답에 성공합니다.
이것이 바로 전체 tcp 서버의 기본 모델이다.
실행 중인 실제 로그 상황:
time="2019-12-31T17:53:52+08:00" level=info msg="address port :8080"
[GIN-debug] Listening and serving HTTP on :8080
time="2019-12-31T17:54:01+08:00" level=info msg=recv ip="127.0.0.1:38936" network=tcp
time="2019-12-31T17:54:01+08:00" level=info msg=" " data=7E80014005018986041210187042775504B004B0010200C77E
time="2019-12-31T17:54:03+08:00" level=info msg=" " data=7E80014005018986041210187042775504B104B1020000C67E
time="2019-12-31T17:54:05+08:00" level=info msg=" " data=7E80014005018986041210187042775504B204B2020000C67E
time="2019-12-31T17:54:08+08:00" level=info msg=" " data=7E80014005018986041210187042775504B304B3020000C67E
time="2019-12-31T17:54:11+08:00" level=info msg=" " data=7E80014005018986041210187042775504B404B4020000C67E
time="2019-12-31T17:54:13+08:00" level=info msg=" " data=7E80014005018986041210187042775504B504B5000200C67E
time="2019-12-31T17:54:16+08:00" level=info msg=" " data=7E80014005018986041210187042775504B604B6020000C67E
time="2019-12-31T17:54:21+08:00" level=info msg=" " data=7E80014005018986041210187042775504B704B7020000C67E
time="2019-12-31T17:54:26+08:00" level=info msg=" " data=7E80014005018986041210187042775504B804B8020000C67E
time="2019-12-31T17:54:31+08:00" level=info msg=" " data=7E80014005018986041210187042775504B904B9020000C67E
time="2019-12-31T17:54:36+08:00" level=info msg=" " data=7E80014005018986041210187042775504BA04BA020000C67E
time="2019-12-31T17:54:41+08:00" level=info msg=" " data=7E80014005018986041210187042775504BB04BB020000C67E
time="2019-12-31T17:54:42+08:00" level=info msg=" " data=7E80014005018986041210187042775504BC04BC000200C67E

좋은 웹페이지 즐겨찾기