如何使用recv()在C++套接字中接收超过65000字节

2024-07-03

我正在 Linux 中使用 C++ 开发客户端服务器应用程序 (TCP)。我想发送超过65,000同时字节。在 TCP 中,最大数据包大小为65,535仅字节。

如何才能无损地发送整个字节?

以下是我在服务器端的代码。

//Receive the message from client socket
if((iByteCount = recv(GetSocketId(), buffer, MAXRECV, MSG_WAITALL)) > 0) 
{
     printf("\n Received bytes %d\n", iByteCount);

     SetReceivedMessage(buffer);
     return LS_RESULT_OK;
}

如果我使用MSG_WAITALL接收字节需要很长时间,因此如何设置标志以一次接收超过 100 万字节。

编辑:MTU 大小为 1500 字节,但 TCP 数据包大小的绝对限制为 65,535。


从上面的评论来看,你似乎不明白如何recv工作原理,或者应该如何使用它。

You really想打电话recv循环中,直到您知道已收到预期的数据量或直到您得到“零字节读取”结果,这意味着另一端已关闭连接。总是如此,无一例外。

如果您需要同时执行其他操作(可能是使用服务器进程!),那么您可能需要检查描述符准备情况poll or epoll第一的。这使您可以在套接字准备就绪时对其进行复用。

您想要这样做的原因是您不知道数据将如何打包以及数据包如何(或何时)到达。加,recv不保证一次读取的数据量。它将提供您调用它时缓冲区中的内容,不多也不少(如果什么都没有,它可能会阻塞,但随后您still不保证恢复时会返回任何特定数量的数据,它仍然可能返回,例如50 字节!)。

即使您总共只发送 5,000 字节,TCP 将其分成 5 个(或 10 个或 20 个)数据包也是完全有效的行为,并且对于recv每次调用它时一次返回 500(或 100、或 20、或 1)个字节。这就是它的工作原理。
TCP 保证您发送的任何内容最终都会到达另一端或产生错误。而且,它保证您发送的任何内容都会按顺序到达。它并不能保证其他太多。最重要的是,它不保证在任何给定时间准备好任何特定数量的数据。
您必须为此做好准备,唯一的方法就是致电recv反复。否则在某些情况下你总是会丢失数据。

MSG_WAITALL原则上应该让它按照你期望的方式工作,但那就是bad行为,并且不保证其有效。如果套接字(或网络堆栈中的某些其他结构)运行违反软限制或硬限制,则可能不会,可能不会满足您的要求。有些限制也很模糊。例如,数字为SO_RCVBUF必须是两倍大由于实现细节,与您期望在 Linux 下收到的内容一样。

服务器应用程序的正确行为应该never取决于诸如“它适合接收缓冲区”之类的假设。原则上,您的应用程序需要准备好使用 1 KB 接收缓冲区接收 TB 级的数据,并且如果需要的话,一次接收 1 个字节的数据块。更大的接收缓冲区将使其更加高效,但仅此而已......它仍然必须以任何方式工作。

事实上,你只会看到超过某个“巨大”限制的失败,这只是运气(或者更确切地说,运气不好)。事实上,在该限制下它显然“工作正常”,这表明您所做的事情是正确的,但事实并非如此。它起作用是一个不幸的巧合。

EDIT:
根据下面评论中的要求,这可能是这样的(代码显然未经测试,买者自负。)

std::vector<char> result;
int size;

char recv_buf[250];

for(;;)
{
    if((size = recv(fd, recv_buf, sizeof(recv_buf), 0)) > 0)
    {
        for(unsigned int i = 0; i < size; ++i)
            result.push_back(recv_buf[i]);
    }
    else if(size == 0)
    {
        if(result.size() < expected_size)
        {
            printf("premature close, expected %u, only got %u\n", expected_size, result.size());
        }
        else
        {
            do_something_with(result);
        }
        break;
    }
    else
    {
        perror("recv");
        exit(1);
    }
}

这将收到您想要的任何数量的数据(或直到operator new throws bad_alloc在分配了几百 MiB 大小的向量之后,但这是一个不同的故事......)。

如果要处理多个连接,则需要添加poll or epoll or kqueue或类似的功能(或...fork),我将把这个作为练习留给读者。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用recv()在C++套接字中接收超过65000字节 的相关文章

  • 如何实现一个单链表队列,使其入队和出队时间复杂度为O(1)?

    这是一个练习 来自CLRS 3rd 10 2 3 通过单向链表 L 实现队列 ENQUEUE 和 DEQUEUE 操作仍然需要 O 1 时间 使用单链表实现队列并不难 我的问题是关于时间复杂度的 如何实现耗时 O 1 的 ENQUEUE 和
  • 哪个STL容器具有线程安全的插入过程?

    哪个STL容器具有线程安全的插入过程 我希望多个线程同时插入同一个容器中 欢迎除 STL 即 Boost 之外的任何实现 STL 容器不是线程安全的 如果您愿意的话 您必须通过自己的同步来强加这一点
  • 查找表到底是如何工作的以及如何实现它们? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我最近编写了一个程序 该程序处理大量 if else 语句以返回特定值 有人建议改用查找表 我的问题是 它们是如何工作的以及您如何实施
  • 在 C++ 中访问静态类变量?

    复制 C 对静态类成员的未定义引用 https stackoverflow com questions 272900 c undefined reference to static class member 如果我有这样的类 结构 head
  • XAML 页面中的 Bindable 值存在问题

    我有一个保龄球回顾示例代码 其中输入了 3 场比赛并总结在系列列中 我遇到的问题是系列列没有按照我的预期进行更新 显然 我做错了什么 但看不到我做错了什么 以下是支持该应用程序的代码
  • 尝试访问 USB 设备时出现 RPC_E_CANTCALLOUT_ININPUTSYNCCALL

    我有这段代码 var searcher new ManagementObjectSearcher root CIMV2 SELECT FROM Win32 DiskDrive foreach var queryObj in searcher
  • 如何有效计算灰度图像中像素的平均“方向”?

    所以我发现我可以将图像转换为灰度图像 如下所示 public static Bitmap GrayScale this Image img var bmp new Bitmap img Width img Height using var
  • 测试用户输入数组中的重复项的最有效方法是什么?

    我正在尝试编写一个模拟器来玩强力球彩票 程序会要求5数字 又名白球 并输入到6元素数组和另一个数字 红色强力球 放入6th 元素 我需要弄清楚如何首先测试重复项5元素但6th 不需要是唯一的 我有一个循环 我认为可以工作 但它甚至不执行并且
  • 使用c#在ms access中更新

    有人可以帮助我的代码有什么问题吗 它是一个更新函数 在我的调试过程中它可以正确执行 但它不会更新我的数据库 我已经在寻找这个问题的答案 但仍然没有成功 我还尝试创建一个新的数据库 希望它有问题 但仍然没有效果 private void up
  • 迁移到新 csproj 格式的 WPF 应用程序上未定义 RunCommand 属性

    我正在尝试将旧 csproj 格式构建的 WPF 应用程序迁移到为 VS2017 定义的新 csproj 格式 我已经能够编译该应用程序 但是当我尝试在 VS2017 下的调试器中启动它时 我收到以下错误消息 无法运行您的项目 未定义 Ru
  • 基本镜面着色

    我正在使用一个生成阴影球体的简单代码 我还没有完全理解数学 但我在玩代码时正在弄清楚它 我想知道如何根据这段代码实现镜面反射着色 有什么建议么 for y 0 y
  • SWIG Python 结构体数组

    我已经搜索了几天 试图弄清楚如何将结构数组转换为 Python 列表 我有一个函数返回指向数组开头的指针 struct foo int member struct foo bar struct foo t malloc sizeof str
  • 如何使文本框的自动完成列表可编辑?

    我有一个包含很多内容的应用程序TextBox使用自动完成的控件 每个人都使用AutoCompleteMode CustomSource从关联的获取自动完成文本AutoCompleteStringCollection 每当用户在其中输入新值时
  • pthread 线程状态

    是否有一种机制可以用来判断 pthread 线程当前是否正在运行或已退出 如果线程尚未退出 pthread join 是否有一种方法能够在特定时间段后超时 如果您仅针对 Linux 请使用http www kernel org doc ma
  • 在 C# 中捕获异常

    我有一个简单的添加按钮 ADD Click 代码是 protected void Add Click object sender EventArgs e string strConnectionString ConfigurationMan
  • 如何解决有关 TcpListener: 请使用 TcpListener(IPAddress localaddr, int port) 的警告?

    我创建了一个新表单 在顶部我做了 using System using System Collections Generic using System ComponentModel using System Data using Syste
  • 安全地抛出在另一个线程上创建的异常 C#

    我想在线程A中捕获异常 然后将异常对象传递给线程B 并从线程B中抛出它 这样安全吗 Thread A try Code that throws exceptions catch Exception e sendToOtherThread e
  • 如何使信号客户端避免表单身份验证?

    我的 MVC 网站在 web config 中有表单授权 现在所有的页面都需要通过授权才能被查看 但是现在我有一个控制台程序 C 控制台程序 这个程序需要发送一些消息到 SignalR 集线器 但是我的 signalR Hub 在我的 MV
  • 基于路由参数的子容器注册

    我们有一个多租户 ASP NET MVC 应用程序 为多个客户端托管预订引擎 这些客户端中的每一个都有多个可以影响 Unity 容器配置的包 我们为每个请求创建一个子容器 并根据通过路由传递的客户端和包参数注册不同的接口实现 目前 我们正在
  • lldb:无法实现:无法获取变量的值

    我用这个命令行编译了一个cpp文件 g g test cpp 它在第 28 行抛出异常 我想通过检查 lldb 中的变量来调查原因 我在第 28 行设置了一个断点并运行a out在LLDB中 lldb n Process 84233 sto

随机推荐