Reputation: 1861
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.)
Upvotes: 1
Views: 495
Reputation: 180058
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()
.
Upvotes: 3