【问题标题】:C: Read from pipe char AND int, simultaneously (tricky one)C:同时从管道 char AND int 读取(棘手的一个)
【发布时间】:2019-04-11 16:12:25
【问题描述】:

我在管道中写一些整数,当我结束时我写“11”。然后,当我从同一个管道读取数据时,我必须获取整数并对它们进行处理,当我得到“11”时,我应该终止。但我想不出任何解决方案可以同时在管道中读取 int 和 char (我知道这是基于 fifo 方法)。

有什么想法吗?

//THIS IS AN EXAMPLE CODE OF WHAT I WANT TO DO 

//I am writing to the pipe
while(CONDITION)
    write(mypipe, &random_int, sizeof(short));
write(mypipe, "1", sizeof("11"));

/* code... */

//I am reading from the pipe
while(TRUE){
    read(mypipe, &received_int, sizeof(short));
    // if strcmp(receiver_int, "11")==0 then exit;
    // else do stuff with receiver_int
}

【问题讨论】:

    标签: c char int pipe


    【解决方案1】:

    管道只是一个字节流,即使您将读取的字节正确解释为 16 位整数和 2 个字符串“11”(在 ASCII 中是字节 31 31),那么您如何分辨“11”除了整数 12593?它们具有相同的二进制表示。

    一种选择是继续读取直到管道终止,这可能适合传输文件。但不允许持续来回消息。

    write(mypipe, &random_int, sizeof(short));
    close(mypipe); // finished writing
    
    // recv
    while (true)
    {
        short received_int;
        if (read(mypipe, &received_int, sizeof(short)) == sizeof(short)) // Not handling the int getting split into two separate read's here
        {
            // Use received_int
        }
        else return; // 0 on close
    }
    

    这就是为什么大多数协议在流的顶部引入消息的概念(无论是文本还是二进制)。例如,您可能有一个 8 位的“操作码”并说 0 是“断开连接”,而 1 是“带有整数的消息”,所以要写一个整数:

     unsigned char opcode = 1;
     short random_int = 55; // Make sure it actually a short, as you used sizeof(short)!
     write(mypipe, &opcode, 1);
     write(mypipe, &random_int, sizeof(short));
    

    要阅读,你先阅读操作码,然后再决定:

    char opcode;
    read(mypipe, &opcode, 1); // CHECK RETURN!
    switch (opcode)
    {
    case 0: return; // Finished
    case 1:
        {
            short received_int;
            read(mypipe, &received_int, sizeof(short)); // CHECK RETURN!
            // Use received_int
            break;
        }
    }
    

    您可能会查看一些现有协议,了解它们如何将不同的内容编码到字节流中。

    【讨论】:

      【解决方案2】:

      我大炮 [原文如此] 想到任何解决方案来同时在管道中读取 int 和 char

      对于这个问题本身没有任何解决方案,因为从管道中读取的既不是字符也不是整数,而是原始字节。其他一切都是关于字节如何解释

      (我知道这是基于 fifo 方法)。

      FIFO 具有与管道完全相同的约束。

      一般来说,如果您想通过任何通信介质传递不同类型的对象,您需要某种格式或协议,使接收方能够按照发送方的意图解释数据。这可以从非常简单到非常复杂。你描述的是一个特别简单的协议(简单,真的):数据由字节对组成,每一对解释为无符号整数的字节,除了有一个特殊的两字节标记数据结束的序列。

      对于这样的协议,我可能会这样写接收方:

      union {
          uint16_t num;
          char s[3];    // Three bytes, not two, to allow for a terminator
      } buffer = { .s = { 0 }};
      
      while (1){
          read(mypipe, &buffer, sizeof(uint16_t));
          if (strcmp(buffer.s, "11") == 0) {
              break;
          }
          // do stuff with buffer.num ...
      }
      

      但是不,您描述的协议没有提供一种方法来区分 "11" 的两个字节与用作整数值的相同两个字节。结果,有一个整数值无法通过此协议发送。很可能是 12593(十进制),这是通过将 "11" 的字符编码为 ASCII 然后将结果重新解释为两字节整数而产生的。

      【讨论】:

      • 谢谢!你是怎么找到12593的?我找不到任何从十进制到 ascii 的在线转换器
      • @NickSt,网上有很多可用的 ASCII 表。谷歌会找到你十几个。他们都会告诉你十进制数字“1”的 ASCII 码是 49(十进制)。 "11" 的两个字节序列因此是 49、49(十进制)。要将其转换为单个 16 位整数,请将更重要的 49 乘以基数 (256) 并加上不重要的。即 256 * 49 + 49 = 257 * 49 = 12593。
      • 但请注意,假设 ASCII 编码为 '1'。尽管 UTF-8、所有 ISO-8859 变体和其他编码也以相同的方式对其进行编码,但该编码不是通用。这就是为什么我在示例代码中执行字符串比较,而不是数字比较。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-04
      • 1970-01-01
      相关资源
      最近更新 更多