【问题标题】:Buffered writes for UNIX sockets?UNIX 套接字的缓冲写入?
【发布时间】:2017-07-31 00:21:14
【问题描述】:

我正在打开一个套接字以将请求直接发送到 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()s,而且我知道对于文件,这可能比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;
}

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

【问题讨论】:

  • 不确定你认为这会如何工作。通常,如果您通过套接字发送某些内容,您会在发送下一个命令之前等待回复。使用缓冲写入,您还拥有缓冲读取和某种消息队列。不确定这是否真的值得开销。

标签: c linux sockets io


【解决方案1】:

正在进行缓冲写入,尽管有点不正确。例如,当你打电话时,

    write(socketfd, packet, 24);

你认为packet 是什么?

现在,您可以创建一个更大的缓冲区,例如unsigned char buffer[4096],然后将memcpy() 输出到其中,最终write() 一次更大的数据块。但是,这仅在一定程度上是有意义的,因为如果您还需要接收对您发送的消息的响应,那么除了在消息边界之外中断传输没有任何优势(除非消息非常长),并且在发送之前缓冲多条消息会使您的代码复杂化。

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

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

【讨论】:

  • 我刚刚尝试将fdopenfwrite 一起使用,但速度要慢得多。我想我会坚持write。谢谢!
  • @étale-cohomology - John 的回答非常简洁,包括重要的建议。正如他所指出的,write 可能只发送 一些 数据(但不是全部) - 在本地测试时您不太可能遇到这种情况。在某些情况下,慢一点可能更安全……我为facil.io 实现了一个带有锁定功能的用户登陆缓冲区,它显然更慢,但总比意外的数据丢失要好。
猜你喜欢
  • 1970-01-01
  • 2011-12-06
  • 2012-04-23
  • 2014-10-13
  • 2010-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多