【问题标题】:Reading from Socket in a loop?循环读取 Socket?
【发布时间】:2020-05-27 13:35:58
【问题描述】:

我正在用 C 语言创建一个服务器/客户端 TCP。

这个想法是让服务器发送相对大量的信息。但是,客户端中的缓冲区只有512的大小(我不想增加这个大小),显然,服务器发送的信息比这个大。让我们想象一下 812 字节。

我想要做的是,在客户端,读取 512 个字节,在客户端的控制台上打印它们,然后读取剩余的字节,并打印它们。

以下是应该发生的事情:

1) 创建服务器,并阻塞在 read() 系统调用中(等待客户端写东西);

2) 创建客户端,在socket中写入东西,然后阻塞在read()上,等待服务器响应;

3) 服务器的 read() 调用返回,现在服务器必须发送大量数据,使用以下代码(在创建新进程后):

dup2(new_socketfd, STDOUT_FILENO); // Redirect to socket

execlp("/application", "application", NULL); // Application that prints the information to send to the client

让我们想象一下“应用程序”向套接字打印了 812 字节的数据。

4) 现在客户端必须读取 812 字节,缓冲区大小为 512。这是我的问题。

我该如何解决这个问题?我想知道我是否可以创建一个循环并读取直到没有可读取的内容,512 x 512 字节。但是一旦没有要读取的内容,客户端就会在 read() 上阻塞。

有什么想法吗?

【问题讨论】:

  • 是的:你需要一个循环。此外:第一个 read() 实际上可以读取 少于 512 个字节! But as soon as there's nothing to read, client will block on read() 如果发件人关闭()连接,则不会。在这种情况下, read() 将返回零。
  • 我无法真正理解您的问题。 TCP 是一种 协议。这意味着从一侧发送的数据包可能会被 网络 拆分或重新组合(在双方之间的所有驱动程序和中继的意义上)。这意味着如果读者不想被不完整的片段咬伤,它应该总是使用循环。如果你想有一个消息的概念,使用 UDP(面向数据包)或使用更高级别的协议来分隔消息。
  • 感谢您的回答!但是我应该如何设置循环呢?什么时候应该爆发?我什么时候知道我阅读了所有内容?
  • @wildplasser 如果发件人关闭()连接,则不会。在这种情况下,read() 将返回零。 是的,我知道。但是,如果我想跳出循环,我需要知道何时阅读了我需要的所有内容。服务器发送的所有内容。我该如何实施?

标签: c sockets buffer


【解决方案1】:

当流中没有数据时,recv 将阻塞。从流中提取的任何数据,长度从recv返回。 您可以编写一个简单的函数来提取完整​​数据,只需使用偏移变量并检查返回值。

这样一个简单的函数就可以了。

ssize_t readfull(int descriptor,char* buffer, ssize_t sizetoread){
    ssize_t offset = 0;
    while (offset <sizetoread) {
        ssize_t read = recv(descriptor,buffer+offset,sizetoread-offset,0);
        if(read < 1){
            return offset;
        }
        offset+=read;
    }
    return offset;
}

此外,服务器通常会在数据完成时发送某种 EOF。服务器可能首先发送要读取的消息的长度,该长度是四个或八个字节的恒定大小,然后它发送数据,以便您提前知道要读取多少。或者,以 HTTP 为例,存在内容长度字段以及 '\r\n' 分隔符。

实际上,没有办法知道服务器有多少数据可以发送给您,这是不切实际的。服务器必须通过某种指标告诉你有多少数据。

由于您自己编写服务器,您可以先发送一个四字节消息,它可以是客户端应该读取多少数据的 int 值。

所以你的服务器可以是这样的:

int sizetosend = arbitrarysize;
send(descriptor,(char*)&sizetosend,sizeof(int),0);

send(descriptor,buffer,sizetosend,0);

然后在您的客户端,读取四个字节,然后是缓冲区。

int sizetoread = 0;
ssize_t read = recv(descriptor,(char*)&sizetoread,sizeof(int),0);
if(read < 4)
  return;

//Now just follow the code I posted above

【讨论】:

    猜你喜欢
    • 2012-11-07
    • 1970-01-01
    • 2013-07-01
    • 2019-03-19
    • 1970-01-01
    • 2019-02-19
    • 2013-07-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多