Linunx API examples
authoryu.dongliang <18588496441@163.com>
Thu, 16 Nov 2023 12:19:15 +0000 (20:19 +0800)
committeryu.dongliang <18588496441@163.com>
Thu, 16 Nov 2023 12:19:15 +0000 (20:19 +0800)
1.txt [new file with mode: 0644]
2.txt [new file with mode: 0644]
Makefile [new file with mode: 0644]
sendmmsg.c [new file with mode: 0644]
shm.c [new file with mode: 0644]
socket_epoll.c [new file with mode: 0644]
socketpair.c [new file with mode: 0644]
socketpair_fd.c [new file with mode: 0644]
socketpair_v.c [new file with mode: 0644]

diff --git a/1.txt b/1.txt
new file mode 100644 (file)
index 0000000..8ad79bd
--- /dev/null
+++ b/1.txt
@@ -0,0 +1 @@
+1111111
diff --git a/2.txt b/2.txt
new file mode 100644 (file)
index 0000000..60d4a44
--- /dev/null
+++ b/2.txt
@@ -0,0 +1 @@
+2222222
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..fb5b52d
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,2 @@
+all:
+       gcc -g -O3 socket_epoll.c -lrt
diff --git a/sendmmsg.c b/sendmmsg.c
new file mode 100644 (file)
index 0000000..c0c9271
--- /dev/null
@@ -0,0 +1,73 @@
+
+
+#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;
+}
+
diff --git a/shm.c b/shm.c
new file mode 100644 (file)
index 0000000..d6d576e
--- /dev/null
+++ b/shm.c
@@ -0,0 +1,178 @@
+#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;
+}
+
diff --git a/socket_epoll.c b/socket_epoll.c
new file mode 100644 (file)
index 0000000..8e10c00
--- /dev/null
@@ -0,0 +1,376 @@
+
+#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;
+}
+
diff --git a/socketpair.c b/socketpair.c
new file mode 100644 (file)
index 0000000..3bfd896
--- /dev/null
@@ -0,0 +1,71 @@
+#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;
+}
+
diff --git a/socketpair_fd.c b/socketpair_fd.c
new file mode 100644 (file)
index 0000000..5a0f409
--- /dev/null
@@ -0,0 +1,132 @@
+#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;
+}
+
diff --git a/socketpair_v.c b/socketpair_v.c
new file mode 100644 (file)
index 0000000..3183655
--- /dev/null
@@ -0,0 +1,101 @@
+#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;
+}
+