如何读取缓冲区中保留内容的缓冲区?

时间:2015-06-02 15:04:57

标签: c linux

我需要跨服务器发送文件,但我需要在响应中添加header。我不知道如何解决这个问题,因为我可以将文件读入缓冲区并使用以下代码一次发送一个缓冲区:

while ((nread = read(in, buffer, sizeof(buffer))) > 0) {
  void *p = buffer;
  while (nread > 0) {
    int nwritten = write(csfd, p, nread);
    if (nwritten <= 0) {
      perror("error while sending the file to the client");
      close(in);
      close(csfd);
    }
    nread -= nwritten;
    p += nwritten;
  }
}
close(in);
close(csfd);

但是由于我需要发送标头,我需要能够将第一个数据块发送为<HEADER>\r\n<DATA-1/33>,然后对套接字的后续写入应该像<DATA-2/33><DATA-3/33><DATA-4/33>等等。

因此,假设我在char header[] = "FOUND 43199 29-33\r\n"中有一个标题,如何将该标题与文件中的第一个数据块一起发送?

也许我可以在复制标题后从数组中的稍后位置开始读取缓冲区?或者有更好的方法?

2 个答案:

答案 0 :(得分:2)

我建议使用压缩结构或带有效负载部分的大缓冲区:

+------------------------------------+  
|                                    |  
|  +----------+----------+--------+  |  
|  |  Header  |  Payload | Footer |  |  
|  +----------+----------+--------+  |  
|    transmit buffer                 |  
+------------------------------------+  

您将发送传输缓冲区,但您可以更改标头,有效负载或页脚,而无需更改发送缓冲区的代码。

编辑1:实施
一种实现方法是使用结构:

struct Transmit_Buffer
{
  Header  m_header;
  uint8_t m_payload[PAYLOAD_CAPACITY];
  Footer  m_footer;
};

另一种实现是字节数组(uint8_t):

uint8_t transmit_buffer[HEADER_SIZE + PAYLOAD_CAPACITY + FOOTER_SIZE];

您可以按索引参考各个部分:

const unsigned int header_index = 0U;
const unsigned int payload_begin = header_index + HEADER_SIZE;
const unsigned int footer_begin = payload_begin + PAYLOAD_CAPACITY;  

使用该结构将是:

Transmit_Buffer buffer;
Send_Data((uint8_t *) &buffer, sizeof(Transmit_Buffer));

使用数组:

Send_Data(&transmit_buffer[0], sizeof(transmit_buffer));

要更改有效负载,您只能访问有效负载部分:

uint8_t * p_payload = &transmit_buffer[payload_begin];

或者

buffer.m_payload

在这种设计中,传输功能并不关心缓冲区中的内容,它的目的是传输数据。

您可以添加另一个创建页眉和页脚部分的图层,然后传输数据。在这种情况下,有效载荷无关紧要,因为它只是简单,无聊的数据。

因此,如果页眉和页脚相同,您可以编写有效负载部分,然后传输缓冲区。

答案 1 :(得分:2)

只需通过套接字发送标头,然后发送有效负载。

如果您担心您的客户必须进行两次阅读而不是一次阅读,并且您有点依赖于必须执行一次阅读,请尽快重写您的客户,因为 TCP不是数据包协议,它是一种不保留应用程序定义边界的流协议。您应该以这样的方式对客户端进行编码,即使一次接收一个字节也是如此。您必须使用有状态解析器,不要假设客户端能够立即read()整个消息,并且不要指望保留发送方边界。

这意味着你的标题应该包含有效负载的长度,或者你应该有一个页脚(但在这种情况下,你必须在有效负载中转义这样的结束序列,这有点不方便)。 / p>

您无法使用不同的write()调用来强制执行应用程序级框架!

相关问题