在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 問答/GO  Linux  HTML/ go TCP 連接到http服務(wù) 如何獲取響應(yīng)?

go TCP 連接到http服務(wù) 如何獲取響應(yīng)?

目標:golang 服務(wù),準備獲取ip:port的banner信息.
如果ip:port為http,即可獲取http響應(yīng),如果為ssh服務(wù),即可獲取ssh服務(wù)輸出信息.如版本信息等.

前置條件:對應(yīng)tcpAddr可以訪問(該http服務(wù)輸出helloworld)
問題:通過代碼

    conn, err := net.DialTimeout("tcp", tcpAddr.String(),timeout)
    if err != nil {
        return false
    }
    reply := make([]byte, 4096)
    conn.Read(reply)
    conn.SetReadDeadline(time.Now().Add(time.Second))
    byte, err := ioutil.ReadAll(conn)
    fmt.Println("srv reply:" + string(byte))
    defer conn.Close()

發(fā)現(xiàn)線程阻塞到read上.
請問如何避免這種阻塞,并能獲取到對應(yīng)endpoint banner信息?

追加:如果先SetReadDeadline,會在超時后解除阻塞.但獲取到的reply為空.

回答
編輯回答
故林

tcp在傳輸層,http在應(yīng)用層

是否能這樣直接使用呢?這個存在疑問。

因為我是沒有這樣用過,基本上服務(wù)端是http,client就使用http協(xié)議去對接。tcp也一樣。

2018年3月13日 21:38
編輯回答
伴謊

使用select吧,多路復(fù)用,不存在所謂的阻塞問題。

2017年10月7日 02:06
編輯回答
綰青絲

假定你要做一個 SSH 與 HTTP 的服務(wù)掃描器,那你可能沒有發(fā)現(xiàn) SSH 與 HTTP 服務(wù)對于客戶端的區(qū)別。

對 SSH 服務(wù)來說,客戶端完成 TCP 連接后,就會收到服務(wù)器發(fā)送的 banner 信息,類似這樣的

SSH-2.0-xxxxxx\r\n...

但是 HTTP 服務(wù)器不一樣,客戶端完成 TCP 連接后,必須發(fā)送一個請求,如

HEAD / HTTP/1.0\r\n\r\n

服務(wù)器才會返回內(nèi)容,如

HTTP/1.0 404 NotFound\r\n
...

下面是參考代碼

package main

import (
    "bufio"
    "bytes"
    "fmt"
    "io"
    "net"
    "sync"
    "time"
)

// 假定是 SSH 服務(wù)。
// 返回 banner 第一行。
func assume_ssh(address string) (string, error) {
    conn, err := net.DialTimeout("tcp", address, time.Second*10)
    if err != nil {
        return "", err
    }
    defer conn.Close()
    tcpconn := conn.(*net.TCPConn)
    // 設(shè)置讀取的超時時間
    tcpconn.SetReadDeadline(time.Now().Add(time.Second * 5))
    reader := bufio.NewReader(conn)
    return reader.ReadString('\n')
}

func split_http_head(data []byte, atEOF bool) (advance int, token []byte, err error) {
    head_end := bytes.Index(data, []byte("\r\n\r\n"))
    if head_end == -1 {
        return 0, nil, nil
    }
    return head_end + 4, data[:head_end+4], nil
}

// 假定是 HTTP 服務(wù)。
// 返回 "/" HTTP 返回頭。
func assume_http(address string) (string, error) {
    conn, err := net.DialTimeout("tcp", address, time.Second*10)
    if err != nil {
        return "", err
    }
    defer conn.Close()
    tcpconn := conn.(*net.TCPConn)
    // 設(shè)置寫的超時時間
    tcpconn.SetWriteDeadline(time.Now().Add(time.Second * 5))
    if _, err := conn.Write([]byte("HEAD / HTTP/1.0\r\n\r\n")); err != nil {
        return "", err
    }
    // 設(shè)置讀的超時時間
    tcpconn.SetReadDeadline(time.Now().Add(time.Second * 5))
    scanner := bufio.NewScanner(conn)
    scanner.Split(split_http_head)
    if scanner.Scan() {
        return scanner.Text(), nil
    }
    err = scanner.Err()
    if err == nil {
        err = io.EOF
    }
    return "", err
}

func check_address(address string) {
    result := make(chan string, 2)
    done := make(chan int, 1)
    var g sync.WaitGroup
    g.Add(2)
    go func() {
        if r, e := assume_ssh(address); e == nil {
            result <- fmt.Sprintf("SSH: %s", r)
        }
        g.Done()
    }()
    go func() {
        if r, e := assume_http(address); e == nil {
            result <- fmt.Sprintf("HTTP: %s", r)
        }
        g.Done()
    }()
    go func() {
        g.Wait()
        done <- 1
    }()
    select {
    case <-done:
        fmt.Printf("# %s\n無結(jié)果", address)
    case r := <-result:
        fmt.Printf("# %s\n%s", address, r)
    }
}

func main() {
    check_address("github.com:80")
    check_address("github.com:22")
}

運行結(jié)果

# github.com:80
HTTP: HTTP/1.1 301 Moved Permanently
Content-length: 0
Location: https:///
Connection: close

# github.com:22
SSH: SSH-2.0-libssh_0.7.0
2017年12月10日 03:30