简体   繁体   中英

Buffered writes for UNIX sockets?

I'm opening a socket to send requests directly to the X server (to bypass using 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));

I must do a bunch of write() s, though, and I know that for files this can be a lot slower than fwrite , due to buffering, since syscalls are expensive. Is there an equivalent function that works with sockets?. Is it even possible to do buffered IO with sockets? (Nevermind that fwrite needs a FILE* stream too, and all I have is a descriptor.)

Here's an example of a function that sends such a request (using 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;
}

(No error checking, for simplicity.)

You are doing buffered writes, albeit a bit incorrectly. When you call, for example,

    write(socketfd, packet, 24);

what do you think packet is?

Now, you can create a larger buffer, say unsigned char buffer[4096] , then memcpy() your output into it and eventually write() larger chunks of data at a time. That makes sense only up to a point however, for if you need to also receive responses to the messages you send then there's no advantage to breaking up the transmission other than at message boundaries (unless messages are exceedingly long), and it will complicate your code to buffer more than one message before sending.

Be aware, however, that write() does not guarantee to send the whole number of bytes requested. Its return value tells you how many it actually did send, and in the event of a short write you probably need to call write() one or more additional times to send the rest of the bytes.

You do have the option of putting most of that on the C library by wrapping the socket file descriptor in a stream via fdopen() , and using the stream I/O functions. In that case, you can configure buffering details via setvbuf() .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM