wayland的client端和server端的跨进程通信是通过socket实现的。本文首先对server端的socket的生成,绑定,监听进行分析,以wayland的源码中自带的weston代码为例,在server端的main函数中,会调用weston_create_listening_socket,该函数的实现如下:
static int
weston_create_listening_socket(struct wl_display *display, const char *socket_name)
{
if (socket_name) {
if (wl_display_add_socket(display, socket_name)) {
weston_log("fatal: failed to add socket: %m\n");
return -1;
}
} else {
socket_name = wl_display_add_socket_auto(display);
if (!socket_name) {
weston_log("fatal: failed to add socket: %m\n");
return -1;
}
}
setenv("WAYLAND_DISPLAY", socket_name, 1);
return 0;
}
若没有指定socket的名称,会自动生成socket名称,为"wayland-0",随后调用_wl_display_add_socket函数完成socket的生成,绑定,该函数的实现如下:
static int
_wl_display_add_socket(struct wl_display *display, struct wl_socket *s)
{
socklen_t size;
s->fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, 0);
if (s->fd < 0) {
return -1;
}
size = offsetof (struct sockaddr_un, sun_path) + strlen(s->addr.sun_path);
if (bind(s->fd, (struct sockaddr *) &s->addr, size) < 0) {
wl_log("bind() failed with error: %m\n");
return -1;
}
if (listen(s->fd, 128) < 0) {
wl_log("listen() failed with error: %m\n");
return -1;
}
s->source = wl_event_loop_add_fd(display->loop, s->fd,
WL_EVENT_READABLE,
socket_data, display);
if (s->source == NULL) {
return -1;
}
wl_list_insert(display->socket_list.prev, &s->link);
return 0;
}
在该函数的调用中,wl_os_socket_cloexec的作用是生成socket,实现如下:
wl_os_socket_cloexec(int domain, int type, int protocol)
{
int fd;
fd = socket(domain, type | SOCK_CLOEXEC, protocol);
if (fd >= 0)
return fd;
if (errno != EINVAL)
return -1;
fd = socket(domain, type, protocol);
return set_cloexec_or_close(fd);
}
生成的socket的函数为socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC,0),其中PF_LOCAL表示unix系统间的通信,SOCK_STREAM标示我们用的是TCP协议,这样会提供按顺序的、可靠、双向、面向连接的比特流,关于SOCK_CLOEXEC的作用可以参考博客。创建socket完成后,将该socket保存在wl_socket结构体s的成员fd中,接下来需要做的是socket的bind操作,它的参数设置在wl_socket_init_for_display_name中完成,该函数的实现如下所示:
static int
wl_socket_init_for_displ