--- /dev/null
+all:
+ gcc -g -O3 socket_epoll.c -lrt
--- /dev/null
+
+
+#define _GNU_SOURCE
+#include<stdio.h>
+#include<stdlib.h>
+#include<stdint.h>
+#include<string.h>
+#include<unistd.h>
+#include<errno.h>
+
+#include<sys/types.h>
+#include<sys/socket.h>
+
+#include<netinet/in.h>
+#include<arpa/inet.h>
+
+
+int main()
+{
+ int fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ printf("socket error, errno: %d\n", errno);
+ return -1;
+ }
+
+ struct iovec msgs[3] = {
+ {"sendmmsg ", strlen("sendmmsg ")},
+ {"hello ", strlen("hello ")},
+ {"world", strlen("world") + 1},
+ };
+
+ struct sockaddr_in addr0;
+ addr0.sin_family = AF_INET;
+ addr0.sin_port = htons(2000);
+ addr0.sin_addr.s_addr = inet_addr("127.0.0.1");
+
+ struct sockaddr_in addr1;
+ addr1.sin_family = AF_INET;
+ addr1.sin_port = htons(3000);
+ addr1.sin_addr.s_addr = inet_addr("127.0.0.1");
+
+ struct mmsghdr h[2];
+ h[0].msg_hdr.msg_name = &addr0;
+ h[0].msg_hdr.msg_namelen = sizeof(addr0);
+ h[0].msg_hdr.msg_iov = msgs;
+ h[0].msg_hdr.msg_iovlen = 3;
+ h[0].msg_hdr.msg_control = NULL;
+ h[0].msg_hdr.msg_controllen = 0;
+ h[0].msg_hdr.msg_flags = 0;
+ h[0].msg_len = 0;
+
+ h[1].msg_hdr.msg_name = &addr1;
+ h[1].msg_hdr.msg_namelen = sizeof(addr1);
+ h[1].msg_hdr.msg_iov = msgs;
+ h[1].msg_hdr.msg_iovlen = 3;
+ h[1].msg_hdr.msg_control = NULL;
+ h[1].msg_hdr.msg_controllen = 0;
+ h[1].msg_hdr.msg_flags = 0;
+ h[1].msg_len = 0;
+
+ int ret = sendmmsg(fd, h, 2, 0);
+ if (ret < 0) {
+ printf("sendmmsg error, errno: %d\n", errno);
+ return -1;
+ }
+ printf(" sendmmsg ret: %d\n", ret);
+
+ printf(" h[0].msg_len: %d\n", h[0].msg_len);
+ printf(" h[1].msg_len: %d\n", h[1].msg_len);
+
+ return 0;
+}
+
--- /dev/null
+#include<stdio.h>
+#include<stdlib.h>
+#include<stdint.h>
+#include<string.h>
+#include<unistd.h>
+#include<errno.h>
+#include<assert.h>
+
+#include<sys/types.h>
+#include<sys/stat.h>
+#include<sys/mman.h>
+#include<sys/wait.h>
+#include<fcntl.h>
+#include<sched.h>
+
+/* 1, Linux API (syscall), 系统提供给用户的一些编程接口 (函数)
+
+ 2, 硬件 对 软件的 "对接框架", OS.
+
+ OS 1970 C语言之父 unix --> posix --> Linux.
+
+ DOS 1980s --> win 95, win 98 --> windows xp (经典)
+
+ Linux 1991 --> 5.4.x --> ubuntu, suse, arch, deepin 深度, debain, fedora
+
+ "硬件越来越多,CPU 型号 越来越多", OS框架 做为 硬件厂商 跟 用户之间的 "缓冲区".
+
+ 2003年,缓冲区溢出 可以执行各种代码,Linux 2.5
+
+ 3, 内存管理、进程管理,文件系统、"设备管理"、网络管理!
+
+ 4, 内存管理: brk() 堆内存 --> sbrk() --> malloc() / free(), mmap() 文件映射,
+
+ 5, 进程管理:fork() / sched_yield() / wait() / exit(),
+
+ pthread_create() / pthread_join() / pthread_yield() / pthread_mutex_lock().
+
+ Linux 内核 在数据结构上不区分 进程和线程,区别在于 内存的共享模式.
+
+ 6, 文件系统,C语言之父的设计模式:"一切都是文件", unix / Linux.
+
+vfs: virtual file system. 函数指针 ==== C++的虚基类, OOP. C风格.
+
+ 内存文件系统,/proc
+ 设备文件, /dev
+ 硬盘文件, / /boot /home
+
+ 总线的驱动, pci / usb
+
+ 网络socket 文件系统 --> 网络子系统
+
+ open() / close() / read() / write() / fcntl() / mmap()
+
+ 共享内存, socketpair().
+
+ 文件API.
+ */
+
+int xchg(volatile int* p)
+{
+ // 理查德 布鲁姆,IA-32,汇编语言程序设计
+ int r = 1;
+ asm volatile("xchg %1, %0"
+ :"=m"(*p), "=r"(r)
+ :"1"(r)
+ :);
+ return r;
+}
+
+int spin_trylock(volatile int* p)
+{
+// Nginx "listen socket 80", 多个进程 监听 同一个socket,
+
+// 一个用户连上来 多个进程同时 "被唤醒",但只有一个进程能截取到用户的连接, "惊群"
+
+ int n = 0;
+ while (1 == xchg(p)) {
+ n++;
+ if (n > 1000)
+ return 0;
+ }
+ return 1;
+}
+
+void spin_lock(volatile int* p)
+{
+ while (1 == xchg(p))
+ sched_yield();
+}
+
+void spin_unlock(volatile int* p)
+{
+ *p = 0;
+}
+
+typedef struct {
+ volatile int lock;
+ volatile int count;
+} shm_t;
+
+// 共享内存里的数据,怎么布局
+
+int main()
+{// shm: shared memory
+/* flags:
+ O_RDWR 可读可写, O_RDONLY 只读, O_WRONLY 只写.
+
+ O_CREAT 如果不存在就创建
+
+ Linux 进程间通信的机制之一,共享内存, socketpair.
+ */
+ int fd = shm_open("shm_obj", O_RDWR | O_CREAT | O_TRUNC, 0666);
+ if (fd < 0) {
+ printf("shm_open error, errno: %d\n", errno);
+ return -1;
+ }
+
+ if (ftruncate(fd, sizeof(shm_t)) < 0) {
+ printf("ftruncate error, errno: %d\n", errno);
+ return -1;
+ }
+
+ shm_t* shm = mmap(NULL, sizeof(shm_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (MAP_FAILED == shm) {
+ printf("mmap error, errno: %d\n", errno);
+ return -1;
+ }
+
+ shm->lock = 0;
+ shm->count = 0;
+
+ int n = 0;
+//-----------------
+// 多进程 程序,需要在父子进程之间 "共享的数据",全在fork()之前申请
+
+// 程序员 对 内核 + 编译器 填坑!
+
+// 人脑的思维 至少 比电脑高一个维度!
+
+ pid_t cpid = fork(); // 把 父进程 复制 一份 到子进程
+ if (-1 == cpid) {
+ printf("fork error\n");
+ return -1;
+ }
+
+ // 父子 进程的 资源 都是一样的
+
+ if (0 == cpid) {
+ while (n < 1000 * 1000) {
+ spin_lock(&shm->lock); // 自旋锁
+ shm->count++;
+ spin_unlock(&shm->lock);
+
+ n++;
+ }
+// 子进程
+
+ exit(0);
+ } else {
+// 父进程
+ while (n < 1000 * 1000) {
+ spin_lock(&shm->lock);
+ shm->count++;
+ spin_unlock(&shm->lock);
+
+ n++;
+ }
+
+ int status;
+ pid_t pid = wait(&status); // 等待子进程退出
+ assert(pid == cpid);
+
+ printf("shm->count: %d\n", shm->count);
+ }
+
+ return 0;
+}
+
--- /dev/null
+
+#include<stdio.h>
+#include<stdlib.h>
+#include<stdint.h>
+#include<string.h>
+#include<unistd.h>
+#include<errno.h>
+#include<assert.h>
+
+#include<sys/types.h>
+#include<sys/socket.h>
+#include<netinet/in.h>
+#include<arpa/inet.h>
+
+#include<sys/epoll.h>
+#include<time.h>
+#include<signal.h>
+
+typedef struct client_s client_t;
+
+#define CLIENT_START 0
+#define CLIENT_CONNECTING 1
+#define CLIENT_CONNECTED 2
+#define CLIENT_HTTP_SENT 3
+#define CLIENT_CLOSE 4
+
+struct client_s
+{
+ int status;
+
+ int epfd;
+ int fd;
+
+ uint32_t events;
+
+ int (*handler)(client_t* c);
+
+ char* write_buf;
+ int write_buf_size;
+ int write_buf_pos;
+
+ int read_bytes;
+
+ time_t time;
+};
+
+int client_connect(client_t* c)
+{
+ c->fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
+ if (c->fd < 0) {
+ printf("socket error, errno: %d\n", errno);
+ return -1;
+ }
+
+ struct sockaddr_in addr;
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(80);
+ addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+
+ int ret = connect(c->fd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in));
+ if (ret < 0) {
+ if (EINPROGRESS != errno) {
+ printf("connect error, errno: %d\n", errno);
+ return -1;
+ }
+ }
+
+ struct epoll_event ev;
+ ev.events = EPOLLOUT | EPOLLRDHUP | EPOLLET;
+ ev.data.ptr = c;
+
+ ret = epoll_ctl(c->epfd, EPOLL_CTL_ADD, c->fd, &ev);
+ if (ret < 0) {
+ printf("epoll_ctl error, errno: %d\n", errno);
+ return -1;
+ }
+
+ printf("c: %p, c->fd: %d, c->status: %d, received: %d\n", c, c->fd, c->status, c->read_bytes);
+ c->status = CLIENT_CONNECTING;
+ return 0;
+}
+
+int client_connect_check(client_t* c)
+{
+ if (!(EPOLLOUT & c->events))
+ return 0;
+
+ int err = -1;
+ int err_len = sizeof(int);
+
+ int ret = getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &err, &err_len);
+ if (ret < 0) {
+ printf("getsockopt error, errno: %d\n", errno);
+ return -1;
+ }
+
+ if (0 == err) {
+ printf("connect ok, err: %d, c: %p, c->fd: %d, c->status: %d, received: %d\n", err, c, c->fd, c->status, c->read_bytes);
+ } else {
+ printf("err: %d, connect error\n", err);
+ return -1;
+ }
+
+#define BUF_SIZE 1024
+
+ c->write_buf = malloc(BUF_SIZE);
+ if (!c->write_buf) {
+ printf("err: malloc error\n");
+ return -1;
+ }
+// printf("c: %p, c->fd: %d, c->status: %d, received: %d\n", c, c->fd, c->status, c->read_bytes);
+
+ struct sockaddr_in addr;
+ socklen_t addr_len = sizeof(addr);
+
+ ret = getsockname(c->fd, (struct sockaddr*)&addr, &addr_len);
+ if (ret < 0) {
+ printf("err: getsockname error, errno: %d\n", errno);
+ return -1;
+ }
+
+ ret = snprintf(c->write_buf, BUF_SIZE - 1, "GET / HTTP/1.1\r\n");
+ assert(ret > 0);
+ int len = ret;
+
+ ret = snprintf(c->write_buf + len, BUF_SIZE - 1 - len, "Host: localhost%d\r\n", ntohs(addr.sin_port));
+ assert(ret > 0);
+ len += ret;
+
+ ret = snprintf(c->write_buf + len, BUF_SIZE - 1 - len, "User-Agent: curl/7.66.0\r\n");
+ assert(ret > 0);
+ len += ret;
+
+ ret = snprintf(c->write_buf + len, BUF_SIZE - 1 - len, "Connection: keep-alive\r\n");
+ assert(ret > 0);
+ len += ret;
+
+ ret = snprintf(c->write_buf + len, BUF_SIZE - 1 - len, "Accept: */*\r\n");
+ assert(ret > 0);
+ len += ret;
+
+ ret = snprintf(c->write_buf + len, BUF_SIZE - 1 - len, "\r\n");
+ assert(ret > 0);
+ len += ret;
+
+ c->write_buf[len] = '\0';
+// printf("http: %s\n", c->write_buf);
+
+ c->write_buf_size = len;
+ c->write_buf_pos = 0;
+
+// c->read_bytes = 0;
+
+ struct epoll_event ev;
+ ev.events = EPOLLOUT | EPOLLRDHUP | EPOLLET;
+ ev.data.ptr = c;
+
+ ret = epoll_ctl(c->epfd, EPOLL_CTL_MOD, c->fd, &ev);
+ if (ret < 0) {
+ printf("epoll_ctl error, errno: %d\n", errno);
+ return -1;
+ }
+
+ c->status = CLIENT_CONNECTED;
+ return 0;
+}
+
+int client_http_send(client_t* c)
+{
+ if (EPOLLOUT & c->events) {
+ printf("send c: %p, c->fd: %d, c->status: %d, received: %d\n", c, c->fd, c->status, c->read_bytes);
+
+ while (c->write_buf_pos < c->write_buf_size) {
+
+ int ret = send(c->fd, c->write_buf + c->write_buf_pos, c->write_buf_size - c->write_buf_pos, 0);
+ if (ret < 0) {
+ if (EAGAIN == errno) {
+ break;
+ } else if (EINTR == errno) {
+ continue;
+ } else {
+ printf("send error, errno: %d\n", errno);
+ return -1;
+ }
+ }
+ assert(ret > 0);
+ c->write_buf_pos += ret;
+ }
+
+ if (c->write_buf_pos == c->write_buf_size) {
+ c->status = CLIENT_HTTP_SENT;
+
+ struct epoll_event ev;
+ ev.events = EPOLLIN | EPOLLRDHUP | EPOLLET;
+ ev.data.ptr = c;
+
+ int ret = epoll_ctl(c->epfd, EPOLL_CTL_MOD, c->fd, &ev);
+ if (ret < 0) {
+ printf("epoll_ctl error, errno: %d\n", errno);
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int client_http_recv(client_t* c)
+{
+ if (EPOLLIN & c->events) {
+ printf("recv c: %p, c->fd: %d, c->status: %d, received: %d\n", c, c->fd, c->status, c->read_bytes);
+
+ while (1) {
+ char response[4096];
+ int ret = recv(c->fd, response, sizeof(response) - 1, 0);
+ if (ret < 0) {
+ if (EAGAIN == errno) {
+ break;
+ } else if (EINTR == errno) {
+ continue;
+ } else {
+ printf("recv error, errno: %d\n", errno);
+ return -1;
+ }
+ } else if (0 == ret) {
+ // printf("ret: %d\n", ret);
+ break;
+ }
+
+ assert(ret > 0);
+ response[ret] = '\0';
+
+ //printf("ret: %d, response: %s\n", ret, response);
+
+ c->read_bytes += ret;
+ }
+ }
+ return 0;
+}
+
+int client_close(client_t* c)
+{
+ printf("close c: %p, c->fd: %d, c->status: %d, received: %d\n", c, c->fd, c->status, c->read_bytes);
+
+ int ret = epoll_ctl(c->epfd, EPOLL_CTL_DEL, c->fd, NULL);
+ if (ret < 0) {
+ printf("epoll_ctl del error, errno: %d\n", errno);
+ return -1;
+ }
+
+ close(c->fd);
+ c->fd = -1;
+
+ free(c->write_buf);
+ c->write_buf = NULL;
+ c->write_buf_pos = 0;
+ c->write_buf_size = 0;
+
+ c->events = 0;
+ c->status = CLIENT_START;
+ return 0;
+}
+
+int client_handler(client_t* c)
+{
+ time_t t;
+ time(&t);
+
+ int ret = -1;
+
+ switch (c->status) {
+ case CLIENT_START:
+ ret = client_connect(c);
+ break;
+ case CLIENT_CONNECTING:
+ ret = client_connect_check(c);
+ break;
+ case CLIENT_CONNECTED:
+ ret = client_http_send(c);
+ break;
+ case CLIENT_HTTP_SENT:
+ ret = client_http_recv(c);
+ break;
+ case CLIENT_CLOSE:
+ ret = client_close(c);
+ break;
+ default:
+ printf("default error\n");
+ break;
+ };
+
+ if (-1 == ret) {
+ c->status = CLIENT_CLOSE;
+ return -1;
+ }
+
+ if (t - c->time > 3 && CLIENT_HTTP_SENT == c->status) {
+ printf("stat c: %p, c->fd: %d, c->status: %d, received: %d\n", c, c->fd, c->status, c->read_bytes);
+
+ c->status = CLIENT_CLOSE;
+ time(&c->time);
+ }
+
+ return ret;
+}
+
+int main()
+{
+ signal(SIGPIPE, SIG_IGN);
+
+ int epfd = epoll_create(1024);
+ if (epfd < 0) {
+ printf("epoll_create error, errno: %d\n", errno);
+ return -1;
+ }
+
+#define N_CLIENTS 4
+ client_t clients[N_CLIENTS] = {0};
+
+ int i;
+ for (i = 0; i < N_CLIENTS; i++) {
+
+ client_t* c = &clients[i];
+
+ c->epfd = epfd;
+ c->status = CLIENT_START;
+ c->fd = -1;
+ c->events = 0;
+ c->handler = client_handler;
+
+ c->read_bytes = 0;
+
+ time(&c->time);
+ }
+
+ while (1) {
+ struct epoll_event events[N_CLIENTS];
+
+ int ret = epoll_wait(epfd, events, N_CLIENTS, 500);
+ if (ret < 0) {
+ printf("epoll_wait error, errno: %d\n", errno);
+ return -1;
+ }
+
+ int i;
+ for (i = 0; i < ret; i++) {
+ struct epoll_event* ev = &events[i];
+
+ client_t* c = ev->data.ptr;
+
+ c->events = ev->events;
+// printf("client_handler i: %d, ret: %d, ev: %p, c: %p, c->fd: %d\n", i, ret, ev, c, c->fd);
+
+ int ret2 = client_handler(c);
+ if (ret2 < 0) {
+ printf("client_handler error, ret2: %d\n", ret2);
+ }
+ }
+
+ for (i = 0; i < N_CLIENTS; i++) {
+
+ client_t* c = &clients[i];
+
+ c->events = 0;
+
+ ret = client_handler(c);
+ if (ret < 0) {
+ printf("client_handler error2, ret: %d\n", ret);
+ }
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
+
--- /dev/null
+#include<stdio.h>
+#include<stdlib.h>
+#include<stdint.h>
+#include<string.h>
+#include<unistd.h>
+#include<errno.h>
+
+#include<sys/types.h>
+#include<sys/socket.h>
+
+
+int main()
+{
+ int sv[2];
+
+ int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
+ if (ret < 0) {
+ printf("socketpair error, errno: %d\n", errno);
+ return -1;
+ }
+
+ pid_t cpid = fork();
+ if (-1 == cpid) {
+ printf("fork error\n");
+ return -1;
+
+ } else if (0 == cpid) {
+ close(sv[0]);
+ sv[0] = -1;
+
+ char* msg = "hello";
+ size_t len = strlen(msg);
+
+ ret = send(sv[1], msg, len + 1, 0);
+ if (ret < 0) {
+ printf("send error, errno: %d\n", errno);
+ return -1;
+ }
+
+ printf(" send ret: %d\n", ret);
+ printf(" pid: %d, send: %s\n", getpid(), msg);
+ } else {
+ pid_t cpid2 = fork();
+ if (-1 == cpid2) {
+ printf("fork error\n");
+ return -1;
+
+ } else if (0 == cpid2) {
+ close(sv[1]);
+ sv[1] = -1;
+
+ usleep(10 * 100);
+
+ char buf[1024] = {0};
+
+ ret = recv(sv[0], buf, sizeof(buf) - 1, 0);
+ if (ret < 0) {
+ printf("recv error, errno: %d\n", errno);
+ return -1;
+ }
+
+ printf(" recv ret: %d\n", ret);
+ printf(" pid: %d, received: %s\n", getpid(), buf);
+ } else {
+ sleep(2);
+ }
+ }
+
+ return 0;
+}
+
--- /dev/null
+#include<stdio.h>
+#include<stdlib.h>
+#include<stdint.h>
+#include<string.h>
+#include<unistd.h>
+#include<errno.h>
+#include<assert.h>
+
+#include <sys/uio.h>
+#include<sys/types.h>
+#include<fcntl.h>
+
+#include<sys/socket.h>
+
+int main()
+{
+ int sv[2];
+
+ int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
+ if (ret < 0) {
+ printf("socketpair error, errno: %d\n", errno);
+ return -1;
+ }
+
+ pid_t cpid = fork();
+ if (-1 == cpid) {
+ printf("fork error\n");
+ return -1;
+
+ } else if (0 == cpid) {
+ close(sv[0]);
+ sv[0] = -1;
+
+ int send_fd = open("./1.txt", O_RDONLY);
+ if (send_fd < 0) {
+ printf("open send_fd error\n");
+ return -1;
+ }
+
+ int send_fd2 = open("./2.txt", O_RDONLY);
+ if (send_fd2 < 0) {
+ printf("open send_fd2 error\n");
+ return -1;
+ }
+
+ struct msghdr h = {0};
+ h.msg_name = NULL;
+ h.msg_namelen = 0;
+ h.msg_flags = 0;
+
+ struct iovec io = { "f", 1};
+ h.msg_iov = &io;
+ h.msg_iovlen = 1;
+
+ struct cmsghdr* cmsg;
+ union {
+ char buf[CMSG_SPACE(sizeof(int))];
+ struct cmsghdr align;
+ } u;
+
+ h.msg_control = u.buf;
+ h.msg_controllen = sizeof(u.buf);
+
+ cmsg = CMSG_FIRSTHDR(&h);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+ *(int*)CMSG_DATA(cmsg) = send_fd2;
+
+ ret = sendmsg(sv[1], &h, 0);
+ if (ret < 0) {
+ printf("sendmsg error, errno: %d\n", errno);
+ return -1;
+ }
+ printf(" sendmsg ret: %d, pid: %d, send_fd2: %d\n", ret, getpid(), send_fd2);
+
+ } else {
+ close(sv[1]);
+ sv[1] = -1;
+
+ usleep(10 * 1000);
+
+ struct msghdr h = {0};
+#if 1
+ h.msg_name = NULL;
+ h.msg_namelen = 0;
+ h.msg_flags = 0;
+
+ char c;
+ struct iovec io = {&c, 1};
+ h.msg_iov = &io;
+ h.msg_iovlen = 1;
+#endif
+#if 1
+ union {
+ char buf[CMSG_SPACE(sizeof(int))];
+ struct cmsghdr align;
+ } u;
+
+ h.msg_control = u.buf;
+ h.msg_controllen = sizeof(u.buf);
+#endif
+ ret = recvmsg(sv[0], &h, 0);
+ if (ret < 0) {
+ printf("recvmsg error, errno: %d\n", errno);
+ return -1;
+ }
+ printf("recvmsg ret: %d\n", ret);
+
+ struct cmsghdr* cmsg;
+ int recv_fd = -1;
+
+ for (cmsg = CMSG_FIRSTHDR(&h); cmsg; cmsg = CMSG_NXTHDR(&h, cmsg)) {
+
+ if (cmsg->cmsg_level == SOL_SOCKET
+ && cmsg->cmsg_type == SCM_RIGHTS) {
+
+ recv_fd = *(int *) CMSG_DATA(cmsg);
+
+ printf(" recvmsg ret: %d, pid: %d, recv_fd: %d\n", ret, getpid(), recv_fd);
+
+ char buf[64] = {0};
+
+ ret = read(recv_fd, buf, sizeof(buf));
+ printf(" read ret: %d, %s, pid: %d, recv_fd: %d\n", ret, buf, getpid(), recv_fd);
+ }
+ }
+ }
+
+ return 0;
+}
+
--- /dev/null
+#include<stdio.h>
+#include<stdlib.h>
+#include<stdint.h>
+#include<string.h>
+#include<unistd.h>
+#include<errno.h>
+
+#include <sys/uio.h>
+#include<sys/types.h>
+
+#include<sys/socket.h>
+
+int main()
+{
+ int sv[2];
+
+ int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
+ if (ret < 0) {
+ printf("socketpair error, errno: %d\n", errno);
+ return -1;
+ }
+
+ pid_t cpid = fork();
+ if (-1 == cpid) {
+ printf("fork error\n");
+ return -1;
+
+ } else if (0 == cpid) {
+ close(sv[0]);
+ sv[0] = -1;
+
+ struct iovec msgs[3] = {
+ {"writev ", strlen("writev ")},
+ {"hello ", strlen("hello ")},
+ {"world", strlen("world") + 1},
+ };
+
+ ret = writev(sv[1], msgs, 3);
+ if (ret < 0) {
+ printf("writev error, errno: %d\n", errno);
+ return -1;
+ }
+ printf(" writev ret: %d, pid: %d\n", ret, getpid());
+
+ sleep(1);
+
+ struct msghdr h;
+ h.msg_name = NULL;
+ h.msg_namelen = 0;
+ h.msg_iov = msgs;
+ h.msg_iovlen = 3;
+ h.msg_control = NULL;
+ h.msg_controllen = 0;
+ h.msg_flags = 0;
+
+ msgs[0].iov_base = "sendmsg ";
+ msgs[0].iov_len = strlen("sendmsg ");
+
+ ret = sendmsg(sv[1], &h, 0);
+ if (ret < 0) {
+ printf("sendmsg error, errno: %d\n", errno);
+ return -1;
+ }
+ printf(" sendmsg ret: %d, pid: %d\n", ret, getpid());
+
+ } else {
+ pid_t cpid2 = fork();
+ if (-1 == cpid2) {
+ printf("fork error\n");
+ return -1;
+
+ } else if (0 == cpid2) {
+ close(sv[1]);
+ sv[1] = -1;
+
+ usleep(10 * 100);
+
+ char buf[1024] = {0};
+
+ ret = recv(sv[0], buf, sizeof(buf) - 1, 0);
+ if (ret < 0) {
+ printf("recv error, errno: %d\n", errno);
+ return -1;
+ }
+ printf(" pid: %d, ret: %d, received: %s\n", getpid(), ret, buf);
+
+ ret = recv(sv[0], buf, sizeof(buf) - 1, 0);
+ if (ret < 0) {
+ printf("recv error, errno: %d\n", errno);
+ return -1;
+ }
+ printf(" pid: %d, ret: %d, received: %s\n", getpid(), ret, buf);
+
+ } else {
+ sleep(2);
+ }
+ }
+
+ return 0;
+}
+