为了账号安全,请及时绑定邮箱和手机立即绑定

go TCP 连接到http服务 如何获取响应?

go TCP 连接到http服务 如何获取响应?

呼唤远方 2019-05-22 15:36:35
目标:golang服务,准备获取ip:port的banner信息.如果ip:port为http,即可获取http响应,如果为ssh服务,即可获取ssh服务输出信息.如版本信息等.前置条件:对应tcpAddr可以访问(该http服务输出helloworld)问题:通过代码conn,err:=net.DialTimeout("tcp",tcpAddr.String(),timeout)iferr!=nil{returnfalse}reply:=make([]byte,4096)conn.Read(reply)conn.SetReadDeadline(time.Now().Add(time.Second))byte,err:=ioutil.ReadAll(conn)fmt.Println("srvreply:"+string(byte))deferconn.Close()发现线程阻塞到read上.请问如何避免这种阻塞,并能获取到对应endpointbanner信息?追加:如果先SetReadDeadline,会在超时后解除阻塞.但获取到的reply为空.
查看完整描述

2 回答

?
慕侠2389804

TA贡献1719条经验 获得超6个赞

假定你要做一个SSH与HTTP的服务扫描器,那你可能没有发现SSH与HTTP服务对于客户端的区别。
对SSH服务来说,客户端完成TCP连接后,就会收到服务器发送的banner信息,类似这样的
SSH-2.0-xxxxxx\r\n...
但是HTTP服务器不一样,客户端完成TCP连接后,必须发送一个请求,如
HEAD/HTTP/1.0\r\n\r\n
服务器才会返回内容,如
HTTP/1.0404NotFound\r\n
...
下面是参考代码
packagemain
import(
"bufio"
"bytes"
"fmt"
"io"
"net"
"sync"
"time"
)
//假定是SSH服务。
//返回banner第一行。
funcassume_ssh(addressstring)(string,error){
conn,err:=net.DialTimeout("tcp",address,time.Second*10)
iferr!=nil{
return"",err
}
deferconn.Close()
tcpconn:=conn.(*net.TCPConn)
//设置读取的超时时间
tcpconn.SetReadDeadline(time.Now().Add(time.Second*5))
reader:=bufio.NewReader(conn)
returnreader.ReadString('\n')
}
funcsplit_http_head(data[]byte,atEOFbool)(advanceint,token[]byte,errerror){
head_end:=bytes.Index(data,[]byte("\r\n\r\n"))
ifhead_end==-1{
return0,nil,nil
}
returnhead_end+4,data[:head_end+4],nil
}
//假定是HTTP服务。
//返回"/"HTTP返回头。
funcassume_http(addressstring)(string,error){
conn,err:=net.DialTimeout("tcp",address,time.Second*10)
iferr!=nil{
return"",err
}
deferconn.Close()
tcpconn:=conn.(*net.TCPConn)
//设置写的超时时间
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
}
//设置读的超时时间
tcpconn.SetReadDeadline(time.Now().Add(time.Second*5))
scanner:=bufio.NewScanner(conn)
scanner.Split(split_http_head)
ifscanner.Scan(){
returnscanner.Text(),nil
}
err=scanner.Err()
iferr==nil{
err=io.EOF
}
return"",err
}
funccheck_address(addressstring){
result:=make(chanstring,2)
done:=make(chanint,1)
vargsync.WaitGroup
g.Add(2)
gofunc(){
ifr,e:=assume_ssh(address);e==nil{
result<-fmt.Sprintf("SSH:%s",r)
}
g.Done()
}()
gofunc(){
ifr,e:=assume_http(address);e==nil{
result<-fmt.Sprintf("HTTP:%s",r)
}
g.Done()
}()
gofunc(){
g.Wait()
done<-1
}()
select{
case<-done:
fmt.Printf("#%s\n无结果",address)
caser:=<-result:
fmt.Printf("#%s\n%s",address,r)
}
}
funcmain(){
check_address("github.com:80")
check_address("github.com:22")
}
运行结果
#github.com:80
HTTP:HTTP/1.1301MovedPermanently
Content-length:0
Location:https:///
Connection:close
#github.com:22
SSH:SSH-2.0-libssh_0.7.0
                            
查看完整回答
反对 回复 2019-05-22
?
Qyouu

TA贡献1786条经验 获得超11个赞

tcp在传输层,http在应用层
是否能这样直接使用呢?这个存在疑问。
因为我是没有这样用过,基本上服务端是http,client就使用http协议去对接。tcp也一样。
                            
查看完整回答
反对 回复 2019-05-22
  • 2 回答
  • 0 关注
  • 1418 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号