草庐IT

go - 如何获取可用 TCP 数据的大小?

coder 2023-07-02 原文

问题

我有一个用例,我需要在第一个 TCP 数据包处Peek,无论它有多长。

片段

我本以为这会起作用:

conn, err := sock.Accept()
if nil != err {
    panic(err)
}

// plenty of time for the first packet to arrive
time.Sleep(2500 * 1000000)

bufConn := bufio.NewReader(conn)
n := bufConn.Buffered()
fmt.Fprintf(os.Stdout, "Size of Buffered Data %d\n", n)

但是,即使我肯定数据已经到达,它仍然显示缓冲了 0 个字节。

完整测试应用

这是一个完整的测试程序:

package main

import (
    "bufio"
    "fmt"
    "net"
    "os"
    "strconv"
    "time"
)

func main () {
    addr := ":" + strconv.Itoa(4080)
    sock, err := net.Listen("tcp", addr)
    if nil != err {
        panic(err)
    }
    conn, err := sock.Accept()
    if nil != err {
        panic(err)
    }

    bufConn := bufio.NewReader(conn)
    var n int
    for {
        n = bufConn.Buffered()
        fmt.Fprintf(os.Stdout, "Size of Buffered Data %d\n", n)
        if 0 != n {
            break
        }
        time.Sleep(2500 * 1000000)
    }
    first, err := bufConn.Peek(n)
    if nil != err {
        panic(err)
    }
    fmt.Fprintf(os.Stdout, "[Message] %s\n", first)
}

测试

以及我的测试方式:

telnet localhost 4080

Hello, World!

这同样有效:

echo "Hello, World!" | nc localhost -p 4080

但是,如果我直接调用 Peek(14),数据显然就在那里。

为什么?

我正在处理一个特定于应用程序的用例 - 在单个端口上多路复用多个协议(protocol)时的魔术字节检测。

理论上数据包大小是不可靠的,但实际上路径中的任何路由器都不会将几个字节的小问候数据包变小,并且应用程序在收到握手响应之前不会发送更多数据。

踢球者

我只支持一种要求服务器首先发送它的 hello 数据包的协议(protocol),这意味着如果在等待 250 毫秒后没有收到数据包,服务器将假定正在使用这个特殊协议(protocol)并发送它的你好。

因此,如果我无需事先执行任何 Read()Peek() 即可知道底层缓冲区中是否存在数据,那将是最好的。

最佳答案

I have a use case where I need to Peek at exactly the first TCP packet, whatever length it may be.

TCP 是一种流协议(protocol),而不是像 UDP 那样的数据报协议(protocol)。这意味着从 TCP 的角度来看,数据包是无关紧要的。它们只是暂时存在于网络中。

应用程序发送的任何数据都将放入连续发送缓冲区,然后由操作系统打包进行传输。这意味着应用程序的多次写入可能导致单个数据包、一次写入多个数据包等。如果数据在传输过程中丢失(即没有 ACK),发送方操作系统甚至可以使用不同大小的数据包进行重新传输。

在线路上接收到的类似数据包将在 OS 内核中重新组装并放入连续读取缓冲区。执行此操作时,线路上可能存在的所有数据包边界都将丢失。因此,应用程序无法找到数据包边界所在的位置。

    n = bufConn.Buffered()

bufConn 不是操作系统套接字缓冲区。 bufConn.Buffered() 只会看到从底层套接字读取到 Go 进程中但尚未被应用程序逻辑使用 bufConn.Read() 检索的数据>:如果您尝试使用 bufConn.Read() 读取单个字节,它实际上会尝试从底层套接字读取更多字节,返回您请求的单个字节并将其余字节保留在bufConn 缓冲区供以后读取。这样做是为了为应用程序逻辑提供更有效的接口(interface)。如果您不想这样做,请不要使用缓冲 I/O。

关于go - 如何获取可用 TCP 数据的大小?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51472020/

有关go - 如何获取可用 TCP 数据的大小?的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  4. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  5. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  6. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  7. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  8. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  9. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  10. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

随机推荐