测试工具之通过wireshark抓包来学习TCP HTTP网络协议
白羽 2018-12-26 来源 :网络 阅读 607 评论 0

摘要:本文将带你了解测试工具通过wireshark抓包来学习TCP HTTP网络协议,希望本文对大家学测试工具有所帮助。

    本文将带你了解测试工具通过wireshark抓包来学习TCP HTTP网络协议,希望本文对大家学测试工具有所帮助。



                       



   

  很多招聘需求上都会要求熟悉TCP/IP协议、socket编程之类的,可见这一块是对于web编程是非常重要的。作为一个野生程序员对这块没什么概念,于是便找来一些书籍想来补补。很多关于协议的大部头书都是非常枯燥的,我特意挑了比较友好的《图解TCP/IP》和《图解HTTP》,但看了一遍仍是云里雾里,找不到掌握了知识后的那种自信。所以得换一种思路来学习————通过敲代码来学习,通过抓包工具来分析网络,抓包神器首推wireshark。本文是自己学习TCP过程的记录和总结。

  1、使用TCP   socket实现服务端和客户端,模拟http请求

  写一个简单的server和client,模拟最简单的http请求,即client发送get请求,server返回hello。这里是用golang写的,最近在学习golang。

  完成之后可以使用postman充当client测试你的server能不能正常返回响应,或者使用完备的http模块测试你的client。

  client向指定端口发送连接请求,连接后发送一个request并收到response断开连接并退出。server可以和不同的客户端建立多个TCP连接,每来了一个新连接就开一个goruntine去处理。

  TCP是全双工的,所谓全双工就是读写有两个通道,互不影响,我当时还纳闷在conn上又读又写不会出毛病吗-_-

  TCP是流式传输,所以要在for中不断的去读取数据,直到断开。注意没有断开连接的时候是读不到EOF的,代码使用了bufio包中的scanner这个API来逐行读取数据,以\n为结束标志。但数据并不都是以\n结尾的,如果读不到结尾,read就会一直阻塞,所以我们需要通过header中的length判断数据的大小。

  我这里偷懒了,只读了header,读到header下面的空行就返回了。加了个超时,客户端5s不理我就断线,如果有数据过来就保持连接。

  server:

  package   main

  import   (

  "bufio"

  "bytes"

  "fmt"

  "io"

  "net"

  "time"

  )

  const   rn = "\r\n"

  func main()   {

  l, err := net.Listen("tcp",   ":8888")

  if err != nil   {

  panic(err)

  }

  fmt.Println("listen   to 8888")

  for {

  conn,   err := l.Accept()

  if err != nil   {

  fmt.Println("conn err:",   err)

  }

  go   handleConn(conn)

  }

  }

  func   handleConn(conn net.Conn) {

  defer   conn.Close()

  defer fmt.Println("关闭")

  fmt.Println("新连接:",   conn.RemoteAddr())

  t :=   time.Now().Unix()

  // 超时

  go   func(t *int64) {

  for {

  if time.Now().Unix()   - *t >= 5   {

  fmt.Println("超时")

  conn.Close()

  return

  }

  time.Sleep(100   * time.Millisecond)

  }

  }(&t)

  for   {

  data, err :=   readTcp(conn)

  if err != nil   {

  if err == io.EOF   {

  continue

  } else   {

  fmt.Println("read err:",   err)

  break

  }

  }

  if   (data > 0) {

  writeTcp(conn)

  t   = time.Now().Unix()

  } else   {

  break

  }

  }

  }

  func   readTcp(conn net.Conn) (int, error) {

  var buf   bytes.Buffer

  var err error

  rd   := bufio.NewScanner(conn)

  total :=   0

  for rd.Scan() {

  var n int

  n,   err = buf.Write(rd.Bytes())

  if err != nil   {

  panic(err)

  }

  buf.Write([]byte(rn))

  total   += n

  fmt.Println("读到字节:",   n)

  if n == 0   {

  break

  }

  }

  err   = rd.Err()

  fmt.Println("总字节数:", total)

  fmt.Println("内容:",   rn, buf.String())

  return total,   err

  }

  func writeTcp(conn   net.Conn) {

  wt := bufio.NewWriter(conn)

  wt.WriteString("HTTP/1.1   200 OK" + rn)

  wt.WriteString("Date: "   + time.Now().String() +   rn)

  wt.WriteString("Content-Length: 5" +   rn)

  wt.WriteString("Content-Type:   text/plain" +   rn)

  wt.WriteString(rn)

  wt.WriteString("hello")

  err   := wt.Flush()

  if err != nil {

  fmt.Println("Flush   err: ",   err)

  }

  fmt.Println("写入完毕",   conn.RemoteAddr())

  }

  client:

  package   main

  import   (

  "bufio"

  "bytes"

  "fmt"

  "net"

  "time"

  )

  const   rn = "\r\n"

  func main()   {

  conn, err := net.Dial("tcp",   ":8888")

  defer   conn.Close()

  defer   fmt.Println("断开")

  if err != nil   {

  panic(err)

  }

  sendReq(conn)

  for   {

  total, err := readResp(conn)

  if   err != nil   {

  panic(err)

  }

  if   total > 0   {

  break

  }

  }

  }

  func   sendReq(conn net.Conn) {

  wt :=   bufio.NewWriter(conn)

  wt.WriteString("GET /   HTTP/1.1" + rn)

  wt.WriteString("Date:   " + time.Now().String() +   rn)

  wt.WriteString(rn)

  err :=   wt.Flush()

  if err != nil   {

  fmt.Println("Flush err: ",   err)

  }

  fmt.Println("写入完毕",   conn.RemoteAddr())

  }

  func   readResp(conn net.Conn) (int, error) {

  var buf   bytes.Buffer

  var err error

  rd   := bufio.NewScanner(conn)

  total :=   0

  for rd.Scan() {

  var n   int

  n, err =   buf.Write(rd.Bytes())

  if err != nil   {

  panic(err)

  }

  buf.Write([]byte(rn))

  if   err != nil   {

  panic(err)

  }

  total   += n

  fmt.Println("读到字节:",   n)

  if n == 0   {

  break

  }

  }

  if   err = rd.Err(); err != nil {

  fmt.Println("read   err:", err)

  }

  if (total   > 0) {

  fmt.Println("resp:", rn,   buf.String())

  }

  return total,   err

  }

   

  2、通过wireshark监听对应端口抓包分析

  server和client做出来了,下面来使用wireshark抓包来看看TCP链接的真容。当然你也可以现成的http模块来收发抓包,不过还是建议自己写一个最简单的。因为现成的模块里面很多细节被隐藏,比如我开始用postman发一个请求但是会建立两个连接,疑似是先发了个HEAD请求。

     

  打开wireshark,默认设置就行了。选择一个网卡,输入过滤条件开始抓包,因为我们是localhost,所以选择loopback。

     

  抓包开始后,启动之前的server监听8888端口,再启动client发送请求,于是便抓到了一次新鲜的TCP请求。

  从图中我们可以清晰的看到三次握手(1-3)和四次挥手(9-12),还有seq和ack的变化,基于TCP的HTTP请求和响应,还有什么window   update(TCP的窗口控制,告诉客户端我这边很空虚,赶紧发射数据)。



   
                   

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标软件测试之测试工具频道!


本文由 @白羽 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程