免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: wcw
打印 上一主题 下一主题

[C] 进程间通信的疑惑? [复制链接]

论坛徽章:
0
31 [报告]
发表于 2009-03-13 09:50 |只看该作者

传递socket句柄我没有办法,但有种其它的解决方案

先说一下。 这是我们公司使用的一种方式, 使用共享内存,  
思路如下:
1. 启动主进程,根据要启动的  子进程的数量 * 单个进程的数据交换空间的大小 计算出共享内存的大小。 创建共享内存
2. 主进程 创建负责与子进程进行通信的子线程
3. 主进程 创建子进程,并为子进程分配共享内存
4. 系统初始化完成.
5. 主进程 接收客户端请求, 把请求分配 给子线程。
6. 子线程接收数据,写入共享内存, 并通知子进程进行处理。
7. 子进程唤醒,从共享内存读取数据。 子进程相应的数据处理, 并把处理结束写入共享内存, 通知主进程, 子进程休眠
8. 子线程读取数据,并发送数据到客户端
9. 下一次处理从第5步开始

论坛徽章:
0
32 [报告]
发表于 2009-03-13 09:51 |只看该作者
用pipe吧,把connfd发到预先创建的子进程中

论坛徽章:
0
33 [报告]
发表于 2009-03-13 10:29 |只看该作者
原帖由 converse 于 2009-3-11 21:23 发表
我建议你改成这样:
父进程创建监听socket,然后fork子进程,由操作系统决定由哪个子进程来进行处理,也就是说当有连接过来的时候由哪个子进程来处理.

现在你这种方式是由程序员来决定选择哪个子进程来处理.


意思是否是这样:

step 1: parent.fork()
step 2: parent.listen() child.listen()
step 3: connection coming
step 4: 操作系统决定是由parent.accept()还是child.accept()

??

论坛徽章:
0
34 [报告]
发表于 2009-03-13 11:34 |只看该作者
给你google来的一个参考


  1. #ifndef AT_FDCWD
  2. #define AT_FDCWD -100
  3. #endif

  4. #if defined(__i386__)
  5. #define __NR_revokeat   325
  6. #else
  7. #error unsupported arch
  8. #endif

  9. int revokeat(int dfd, const char *path)
  10. {
  11.         return syscall(__NR_revokeat, dfd, path);
  12. }

  13. static void panic(const char *s)
  14. {
  15.         perror(s);
  16.         exit(1);
  17. }

  18. /* I test here for __sun for lack of anything better, but I
  19. * mean Solaris 2.6. The idea of undefining SCM_RIGHTS is
  20. * to force the headers to behave BSD 4.3 way which I have
  21. * tested to work.
  22. *
  23. * In general, if you have compilation errors, you might consider
  24. * adding a test for your platform here.
  25. */
  26. #if defined(__sun)
  27. #undef SCM_RIGHTS
  28. #endif

  29. #ifdef SCM_RIGHTS

  30. /* It seems various versions of glibc headers (i.e.
  31. * /usr/include/socketbits.h) miss one or more of these */

  32. #ifndef CMSG_DATA
  33. # define CMSG_DATA(cmsg) ((cmsg)->cmsg_data)
  34. #endif

  35. #ifndef CMSG_NXTHDR
  36. # define CMSG_NXTHDR(mhdr, cmsg) __cmsg_nxthdr (mhdr, cmsg)
  37. #endif

  38. #ifndef CMSG_FIRSTHDR
  39. # define CMSG_FIRSTHDR(mhdr) \
  40.   ((size_t) (mhdr)->msg_controllen >= sizeof (struct cmsghdr)          \
  41.    ? (struct cmsghdr *) (mhdr)->msg_control : (struct cmsghdr *) NULL)
  42. #endif

  43. #ifndef CMSG_ALIGN
  44. # define CMSG_ALIGN(len) (((len) + sizeof (size_t) - 1) \
  45.                          & ~(sizeof (size_t) - 1))
  46. #endif

  47. #ifndef CMSG_SPACE
  48. # define CMSG_SPACE(len) (CMSG_ALIGN (len) \
  49.                          + CMSG_ALIGN (sizeof (struct cmsghdr)))
  50. #endif

  51. #ifndef CMSG_LEN
  52. # define CMSG_LEN(len)   (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
  53. #endif

  54. union fdmsg {
  55.         struct cmsghdr h;
  56.         char buf[CMSG_SPACE(sizeof(int))];
  57. };
  58. #endif

  59. /* Tested to work on perl 5.005_03
  60. *   Linux-2.2.14 glibc-2.0.7 (libc.so.6) i586  BSD4.4
  61. *   Linux-2.0.38 glibc-2.0.7 (libc.so.6) i586  BSD4.4
  62. *   SunOS-5.6, gcc-2.7.2.3, Sparc BSD4.3
  63. * see also: linux/net/unix/af_unix.c
  64. */


  65. int
  66. sendfd(sock_fd, send_me_fd)
  67.         int sock_fd;
  68.         int send_me_fd;
  69. {
  70.         int ret = 0;
  71.         struct iovec  iov[1];
  72.         struct msghdr msg;

  73.         iov[0].iov_base = &ret;  /* Don't send any data. Note: der Mouse
  74.                                   * <[email]mouse@Rodents.Montreal.QC.CA[/email]> says
  75.                                   * that might work better if at least one
  76.                                   * byte is sent. */
  77.         iov[0].iov_len  = 1;

  78.         msg.msg_iov     = iov;
  79.         msg.msg_iovlen  = 1;
  80.         msg.msg_name    = 0;
  81.         msg.msg_namelen = 0;

  82.         {
  83. #ifdef SCM_RIGHTS
  84.                 /* New BSD 4.4 way (ouch, why does this have to be
  85.                  * so convoluted). */

  86.                 union  fdmsg  cmsg;
  87.                 struct cmsghdr* h;

  88.                 msg.msg_control = cmsg.buf;
  89.                 msg.msg_controllen = sizeof(union fdmsg);
  90.                 msg.msg_flags = 0;

  91.                 h = CMSG_FIRSTHDR(&msg);
  92.                 h->cmsg_len   = CMSG_LEN(sizeof(int));
  93.                 h->cmsg_level = SOL_SOCKET;
  94.                 h->cmsg_type  = SCM_RIGHTS;
  95.                 *((int*)CMSG_DATA(h)) = send_me_fd;
  96. #else
  97.                 /* Old BSD 4.3 way. Not tested. */
  98.                 msg.msg_accrights = &send_me_fd;
  99.                 msg.msg_accrightslen = sizeof(send_me_fd);
  100. #endif

  101.                 if (sendmsg(sock_fd, &msg, 0) < 0) {
  102.                         ret = 0;
  103.                 } else {
  104.                         ret = 1;
  105.                 }
  106.         }
  107.         /*fprintf(stderr,"send %d %d %d %d\n",sock_fd, send_me_fd, ret, errno);*/
  108.         return ret;
  109. }

  110. int
  111. recvfd(sock_fd)
  112.         int sock_fd;
  113. {
  114.         int count;
  115.         int ret = 0;
  116.         struct iovec  iov[1];
  117.         struct msghdr msg;

  118.         iov[0].iov_base = &ret;  /* don't receive any data */
  119.         iov[0].iov_len  = 1;

  120.         msg.msg_iov = iov;
  121.         msg.msg_iovlen = 1;
  122.         msg.msg_name = NULL;
  123.         msg.msg_namelen = 0;

  124.         {
  125. #ifdef SCM_RIGHTS
  126.                 union fdmsg  cmsg;
  127.                 struct cmsghdr* h;

  128.                 msg.msg_control = cmsg.buf;
  129.                 msg.msg_controllen = sizeof(union fdmsg);
  130.                 msg.msg_flags = 0;

  131.                 h = CMSG_FIRSTHDR(&msg);
  132.                 h->cmsg_len   = CMSG_LEN(sizeof(int));
  133.                 h->cmsg_level = SOL_SOCKET;  /* Linux does not set these */
  134.                 h->cmsg_type  = SCM_RIGHTS;  /* upon return */
  135.                 *((int*)CMSG_DATA(h)) = -1;

  136.                 if ((count = recvmsg(sock_fd, &msg, 0)) < 0) {
  137.                         ret = 0;
  138.                 } else {
  139.                         h = CMSG_FIRSTHDR(&msg);   /* can realloc? */
  140.                         if (   h == NULL
  141.                             || h->cmsg_len    != CMSG_LEN(sizeof(int))
  142.                             || h->cmsg_level  != SOL_SOCKET
  143.                             || h->cmsg_type   != SCM_RIGHTS ) {
  144.                                 /* This should really never happen */
  145.                                 if (h)
  146.                                   fprintf(stderr,
  147.                                     "%s:%d: protocol failure: %d %d %d\n",
  148.                                     __FILE__, __LINE__,
  149.                                     h->cmsg_len,
  150.                                     h->cmsg_level, h->cmsg_type);
  151.                                 else
  152.                                   fprintf(stderr,
  153.                                     "%s:%d: protocol failure: NULL cmsghdr*\n",
  154.                                     __FILE__, __LINE__);
  155.                                 ret = 0;
  156.                         } else {
  157.                                 ret = *((int*)CMSG_DATA(h));
  158.                                 /*fprintf(stderr, "recv ok %d\n", ret);*/
  159.                         }
  160.                 }
  161. #else
  162.                 int receive_fd;
  163.                 msg.msg_accrights = &receive_fd;
  164.                 msg.msg_accrightslen = sizeof(receive_fd);

  165.                 if (recvmsg(sock_fd, &msg, 0) < 0) {
  166.                         panic("recvmsg");
  167.                         ret = 0;
  168.                 } else {
  169.                         ret = receive_fd;
  170.                 }
  171. #endif
  172.         }

  173.         return ret;
  174. }

  175. int main(int argc, char *argv[])
  176. {
  177.         int fd, err, new_fd;
  178.         int sockpair[2];
  179.         char buf[1024];

  180.         fd = open(argv[1], O_RDWR);
  181.         if (fd < 0)
  182.                 panic("open");

  183.         err = socketpair(PF_LOCAL, SOCK_DGRAM, 0, sockpair);
  184.         if (err)
  185.                 panic("socketpair");

  186.         if (!sendfd(sockpair[0], fd))
  187.                 panic("sendfd");

  188.         close(fd);

  189.         err = revokeat(AT_FDCWD, argv[1]);
  190.         if (err)
  191.                 panic("revokeat");

  192.         new_fd = recvfd(sockpair[1]);
  193.         if (new_fd <= 0)
  194.                 panic("recvfd");

  195.         if (read(new_fd, buf, 1024) != -1 || errno != EBADF) {
  196.                 printf("Failed: can read from SCM_RIGHTS descriptor\n");
  197.                 exit(1);
  198.         }

  199.         printf("Test OK.\n");
  200.         return 0;
  201. }

复制代码

论坛徽章:
0
35 [报告]
发表于 2009-03-13 15:06 |只看该作者
Current Unix systems provide a way to pass any open descriptor from one process to any other process. That is, there is no need for the processes to be related, such as a parent and its child. The technique requires us to first establish a Unix domain socket between the two processes and then use sendmsg to send a special message across the Unix domain socket. This message is handled specially by the kernel, passing the open descriptor from the sender to the receiver.

论坛徽章:
0
36 [报告]
发表于 2009-03-13 15:56 |只看该作者
这个是可以实现的,我以前做过一个类似的。
主进程先fork()很多子进程,然后accept之后把套接字传递给子进程,让子进程和客户端通讯。自己继续监听。
麻烦的地方是,系统繁忙时候处理起来很麻烦。

论坛徽章:
0
37 [报告]
发表于 2009-03-13 16:43 |只看该作者
传递SOCKFD的过程也是有代价的. 至少使程序看起来多了不少麻烦.

原帖由 yaoaiguo 于 2009-3-13 15:56 发表
这个是可以实现的,我以前做过一个类似的。
主进程先fork()很多子进程,然后accept之后把套接字传递给子进程,让子进程和客户端通讯。自己继续监听。
麻烦的地方是,系统繁忙时候处理起来很麻烦。

论坛徽章:
0
38 [报告]
发表于 2009-03-13 18:06 |只看该作者
step 1: parent.fork() 子进程池
step 2: parent.listen()
step 3: then all childs run accept() and 处理连接 (识操作系统支持情况是否需要自己同步)
         parent维护子进程存活

上面也是apache prefork 方式的处理方式 并不是上面有兄弟理解的需要考虑怎么传送fd
我想搂主的老师是不是比较熟悉apache源码

论坛徽章:
0
39 [报告]
发表于 2009-03-13 18:27 |只看该作者
我昨天实现了一个进程池
http://blog.chinaunix.net/u1/37472/showart_1862390.html
不过还是没有使用到“文件描述符传递”,因为我让子进程自己去accept,而不是父进程accept后把connfd传给子进程。不过“文件描述符传递”的使用我还要继续学习下,虽然这里没用到,但我觉得这东西在以后的工作中会很有用。

代码写得很丑,各位轻拍。

论坛徽章:
0
40 [报告]
发表于 2009-03-14 11:38 |只看该作者
用pipe()管道啊
父进程给子进程传数据
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP