UNIX套接字的缓冲写入?

时间:2017-03-09 20:48:12

标签: c linux sockets io

我打开套接字直接向X服务器发送请求(绕过使用Xlib / XCB)。

#define X11_OP_REQ_CREATE_WINDOW  0x01
#define X11_OP_REQ_MAP_WINDOW     0x08
#define X11_OP_REQ_CREATE_PIX     0x35
#define X11_OP_REQ_CREATE_GC      0x37
#define X11_OP_REQ_PUT_IMG        0x48

...

  struct sockaddr_un serv_addr = {0};
  int socketfd = socket(AF_UNIX, SOCK_STREAM, 0);  // Create the socket!
  serv_addr.sun_family = AF_UNIX;
  strcopy(serv_addr.sun_path, "/tmp/.X11-unix/X0", 0);
  int srv_len = sizeof(struct sockaddr_un);
  connect(socketfd,(struct sockaddr*)&serv_addr, sizeof(serv_addr));

我必须做一堆write(),但我知道对于文件来说这可能比fwrite慢很多,因为缓冲,因为系统调用很昂贵。是否有与套接字一起使用的等效函数?甚至可以用套接字做缓冲IO吗? (没关系fwrite也需要一个FILE*流,我所拥有的只是一个描述符。)

以下是发送此类请求的函数示例(使用write)。

void x11_put_img(int socketfd, struct x11_connection* conn, uint8 format, uint32 target, uint32 gc, uint16 w, uint16 h, uint16 x, uint16 y, uint8 depth, uint32* data){
    uint32 packet[6];
    uint16 length = ((w*h)) + 6;

    packet[0] = X11_OP_REQ_PUT_IMG | format<<8 | length<<16;
    packet[1] = target;
    packet[2] = gc;
    packet[3] = w | h<<16;
    packet[4] = x | y<<16;
    packet[5] = depth<<8;

    write(socketfd, packet, 24);
    write(socketfd, data, (w*h)*4);

    return;
}

(为简单起见,没有错误检查。)

1 个答案:

答案 0 :(得分:3)

正在做缓冲写入,虽然有点不正确。例如,当你打电话时,

    write(socketfd, packet, 24);

您认为packet是什么?

现在,您可以创建一个更大的缓冲区,比如unsigned char buffer[4096],然后将memcpy()输出到其中,最后创建write()个更大的数据块。然而,只有在某一点上才有意义,因为如果您还需要接收响应来发送消息,那么除了消息边界之外打破传输没有任何优势(除非消息非常长) ),它会使你的代码复杂化,以便在发送之前缓冲多条消息。

但请注意,write()不保证发送所请求的全部字节数。它的返回值告诉你它实际发送了多少,如果写入很短,你可能需要再调用write()一次或多次来发送剩余的字节。

通过fdopen()将流套接字文件描述符包装在流中,并使用流I / O函数,您可以选择将大部分内容放在C库中。在这种情况下,您可以通过setvbuf()配置缓冲详细信息。