无双 回复于:2003-07-04 22:51:21 |
精华中有
你试过了没有 |
stevenyi 回复于:2003-07-05 02:47:57 |
没找到啊,给出URL好吗? |
无双 回复于:2003-07-05 10:31:51 |
按标题为
描述 查找C/C++版内贴子 有讨论 |
stevenyi 回复于:2003-07-05 23:24:03 |
SCO上不成功,aix和hp都可以 |
无双 回复于:2003-07-06 00:11:40 |
SCO上你使用的是什么方法
ioctl还是sendmsg 可能它只支持一种方式 |
stevenyi 回复于:2003-07-06 01:25:31 |
2种方式都不行 |
stevenyi 回复于:2003-07-06 01:27:43 |
SCO,AIX,HPUX分别属于SVR4还是BSD呢? |
蓝色键盘 回复于:2003-07-07 10:42:37 |
SCO宣称可以传递描述子,这些内容在流实现部分给予了说明。
然而事实上SCO对于流的处理,很多并不是真正的实现。 对于管道的处理,SCO中也存在不少问题。 大多数系统,传递描述字可以使用sendmsg(recvmsg)来实现,这种方法是较晚的方法,在此之前很多人喜欢用ioctl(SENDFD)实现。在SCO中,第一中方法,用sendmsg会导致描述字无效(sco并没有把一个有效的描述字当作流来处理),然而,就算sendmsg成功传递了,sco仍然存在另外一个问题,就是sco在处理流管道的过程中产生"惊群"现象,流管道的激活活导致进程池中所有的进程返回,事实上,真正服务的仅仅是一个进程。这样带来的问题是,需要应用程序来处理这些细节。 第二种方法,ioctl根本就不支持。 类似的机制在aix,hp可以实现。 如果在sco上面想实现进程池的机制,建议采用aclearcase/" target="_blank" >ccept+锁。可以正常工作。 |
stevenyi 回复于:2003-07-07 13:53:59 |
[quote:571c42c2eb="蓝色键盘"]......... 就是sco在处理流管道的过程中产生"惊群"现象,流管道的激活活导致进程池中所有的进程返回,事实上,真正服务的仅仅是一个进程。.........[/quote:571c42c2eb]
不太明白,能详细解释一下吗? "惊群"是导致进程结束吗? |
gadfly 回复于:2003-07-07 15:37:37 |
不是导致结束,而是导致所有的进程都从相同的读中返回,但是只有一个成功。 |
stevenyi 回复于:2003-07-07 17:30:14 |
所有的进程都从相同的读中返回?
是指从相同的stream pipe读,还是从client socket读? |
蓝色键盘 回复于:2003-07-07 19:12:42 |
能够产生"惊群"现象的情况很多。例如pipe,accept等。
具体的含义是:一种操作导致了和该操作相关的所有其它进程或线程产生相同的行为,该行为成为"惊群"。 对于"惊群"后怎么处理,完全是应用程序的事情。 如果你在sco系统中实现进程池的话,使用accept+锁也有避免"惊群"产生的原因。 对于管道而言。加入父子之前创建了100个,那么在进程递交描述字的过程中,会出现所有子进程阻塞返回的情形。因此你必须处理这正情况。 |
stevenyi 回复于:2003-07-07 19:33:38 |
找了一段用流设备实现的s_pipe的代码,已经可以传递描述符了。父进程在负责accept tcp连接,然后把socket传送给子进程;子进程只是在s_pipe的另一端recv_fd. 没发生“惊群”的现象。但有2个问题
1。 select对于该s_pipe无效,只能用poll 2. fcntl/ioctl设置非阻塞属性不成功 |
蓝色键盘 回复于:2003-07-07 19:56:50 |
你使用一个Pipe还是多个?
用ioctl(SENDFD)能够成功吗? |
stevenyi 回复于:2003-07-07 20:37:24 |
多个(6个),ioctl(I_SENDFD),ioctl(I_RECVFD)都可以 |
stevenyi 回复于:2003-07-07 21:15:06 |
那2个问题有什么好办法解决吗? |
gadfly 回复于:2003-07-08 00:11:25 |
参考unix高级编程15章吧 |
蓝色键盘 回复于:2003-07-08 11:14:41 |
呵呵,我总算找到了原因。
在aix,hp和sco上面,也是实现进程池,我单独为了sco写了另外的一个版本,当时我以次尝试了如下几种方案: 1、创建管道pipe,传递描述字用sendmsg和getmsg。结果失败。 2、创建管道pipe,传递描述字用ioctl(I_SENDFD)和getmsg(或者ioctl(I_RECVFD)。结果失败。 3、创建流管道socketpair,传递描述字用sendmsg和getmsg,或者用ioctl(SENDFD,RECVFD),都失败。 4、查阅sco资料,有些地方说明sco在流方面存在一些先天不足。无奈,采用accept+锁机制,成功。 当时运行sco的版本为5.04和5.05。 stevenyi兄帮助我提供了思路,昨天下班,找了大量的sco的技术资料查阅。最终找到原因。为了不让更多的兄弟像我一样走弯路。我不敢独享,把解决的办法和结果告诉大家。 我看到了SCO OpenServer Release 5.0.6中对于流设备做了如下的描述 [code:1:ad377c12dc] /dev/spx must exist and the sp driver must be linked into the kernel before stream pipes can be used. The sp driver is part of the standard distribution, however, the special file /dev/spx is not. (Note that /dev/spx is created if you install SCO TCP/IP.) Use the mknod(C) command to create /dev/spx [/code:1:ad377c12dc] 按照上面的说明,su - root 运行了如下的命令 [code:1:ad377c12dc] /etc/mknod /dev/spx c 40 60 注意该设备的权限信息为:crw-rw-rw- 不要做更改. [/code:1:ad377c12dc] 把当年的代码拿出来,更改为ioctl方式测试,成功了! 简单的伪代码如下: 创建流管道: [code:1:ad377c12dc] socketpair或者 if ( ( fd[0] = open(SPX, O_RDWR) ) < 0 ) return(-1); if ( ( fd[1] = open(SPX, O_RDWR) ) < 0 ) return(-1); if ( ioctl(fd[0], I_FDINSERT, &s) < 0 ) return(-1); [/code:1:ad377c12dc] 写描速字到管道: [code:1:ad377c12dc] if ( ioctl(fd, I_SENDFD, sendfd) < 0 ) 或者 struct msghdr和struct iovec 结合 sendmsg 该中办法可以参看unix环境高级编程. [/code:1:ad377c12dc] 从管道读取描述字: [code:1:ad377c12dc] if ( ioctl(fd, I_RECVFD, (char *) &s) < 0 ) 成员s.fd便是读取到的描述字,注意s为结构体:struct strrecvfd 。 采用recvmsg,改种办法,需要对齐,比较麻烦。 [/code:1:ad377c12dc] 可以看出,5.06的称述对于5。05来说同样使用,差点冤枉sco一次。呵呵 为了大家便于彻底的掌握,我把描述字相关的5.06的描述罗列如下: [code:1:ad377c12dc] STREAMS ioctl(S) commands perform a variety of control functions on ``streams.'' The arguments command and arg are passed to the file designated by fildes and are interpreted by the ``stream head.'' Certain combinations of these arguments may be passed to a module or driver in the stream. fildes is an open file descriptor that refers to a stream. command determines the control function to be performed as described below. arg represents additional information that is needed by this command. The type of arg depends upon the command, but it is generally an integer (int), or a pointer to a command-specific data structure. Since these STREAMS commands are a subset of ioctl, they are subject to the errors described there. In addition to those errors, the call will fail with errno set to EINVAL, without processing a control function, if the stream referenced by fildes is linked below a multiplexer, or if command is not a valid value for a stream. Also, as described in ioctl(S), STREAMS modules and drivers can detect errors. In this case, the module or driver sends an error message to the stream head containing an error value. This causes subsequent system calls to fail with errno set to this value. 由于ioctl的操作选项太多,此处只是罗列了I_SENDFD和O_RECVFD。 I_SENDFD Request the stream associated with fildes to send a message, containing a file pointer, to the stream head at the other end of a stream pipe. The file pointer corresponds to arg, which must be an integer file descriptor. I_SENDFD converts arg into the corresponding system file pointer. It allocates a message block and inserts the file pointer in the block. The user id and group id associated with the sending process are also inserted. This message is placed directly on the read queue (see Intro(S)) of the stream head at the other end of the stream pipe to which it is connected. On failure, errno is set to one of the following values: [EAGAIN] The sending stream is unable to allocate a message block to contain the file pointer. [EAGAIN] The read queue of the receiving stream head is full and cannot accept the message sent by I_SENDFD. [EBADF] arg is not a valid, open file descriptor. [EINVAL] fildes is not connected to a stream pipe. [ENXIO] Hangup received on fildes. I_RECVFD Retrieve the file descriptor associated with the message sent by an I_SENDFD ioctl over a stream pipe. arg is a pointer to a data buffer large enough to hold an strrecvfd data structure containing the following members: int fd; unsigned short uid; unsigned short gid; char fill[8]; fd is an integer file descriptor. uid and gid are the user id and group id, respectively, of the sending stream. If O_NDELAY is not set (see open(S)), I_RECVFD will block until a message is present at the stream head. If O_NDELAY is set, I_RECVFD will fail with errno set to EAGAIN if no message is present at the stream head. If the message at the stream head is a message sent by an I_SENDFD, a new user file descriptor is allocated for the file pointer contained in the message. The new file descriptor is placed in the fd field of the strrecvfd structure. The structure is copied into the user data buffer pointed to by arg. On failure, errno is set to one of the following values: [EAGAIN] A message was not present at the stream head read queue, and the O_NDELAY flag is set. [EBADMSG] The message at the stream head read queue was not a message containing a passed file descriptor. [EFAULT] arg points outside the allocated address space. [EMFILE] No files file descriptors are currently open. [ENXIO] Hangup received on fildes. [/code:1:ad377c12dc] SCO对于流设备的描述如下:(很有用,如果在sco上操作流设备,不得不看) [code:1:ad377c12dc] A stream pipe provides a full-duplex communication path between two processes, and allows the passing of file descriptors. The processes can communicate over a stream pipe using ordinary read(S) and write(S) system calls. Stream pipes are used by dbxtra(CP) and the X server. The STREAMS pipe device driver sp is accessed through the character special file /dev/spx. ioctl(S) commands for controlling the sp driver are described in the streamio(M) manual page. sp is an example of a ``clone'' device; successive open(S) calls on /dev/spx cause the driver to make available arbitrary and unique minor devices. (Clone devices represent all their minor devices using only one special file. See clone(M).) Each open on /dev/spx returns a file descriptor to the stream head of a different loop-back driver (input on the descriptor is echoed straight back as output that can be read from the descriptor). Unnamed stream pipes may be used whenever a parent process needs to establish full-duplex communication between itself and a child process yet to be spawned. The parent process opens /dev/spx twice; the two file descriptors returned each point to the stream head of a loop-back driver. The parent then connects the two loop-back drivers using the I_FDINSERT ioctl command (see streamio(M)). A write to either descriptor can then be read from the other. After the parent forks, it closes one file descriptor and the child closes the other. Parent and child communicate by writing to or reading from the remaining descriptor. (If necessary, the I_SRDOPT ioctl command can be used to change read modes.) Named stream pipes allow full-duplex communication between an arbitrary pair of processes (that are not necessarily parent and child). A named stream pipe is created by calling mknod(S) to bind a name to a unnamed stream pipe. The mknod system call, however, requires root privilege to create this file type. An auxiliary program can be used to create the named stream pipe provided that it has set its effective user ID to root. Any process may then open the named stream pipe and write to it, subject to the normal filesystem permissions. The named stream pipe remains in existence after the process that created it exits. File descriptors can be sent from one process to another down a stream pipe. Descriptors are sent and received using the I_SENDFD and I_RECVFD ioctl commands. The receiving process also has access to the effective user and group IDs of the sending process if these are needed for the purpose of security. Typically, a .network server daemon would first create and open a named stream pipe. A client opens the named pipe and sends a message to the server requesting connection; the server establishes the connection by sending a file descriptor down the pipe. Extra functionality can be added to a stream pipe by pushing further STREAMS modules onto it. Diagnostics CONFIG: sp: spclose - Cannot allocate STREAMS block CONFIG: sp: spopen - Cannot allocate STREAMS block A STREAMS message block could not be allocated. You may need to increase the value of NSTRPAGES, the maximum amount of memory that STREAMS will use. This tunable kernel parameter uses units of 4KB pages. The default value is 125 pages (500KB); this can be increased with configure(ADM). [/code:1:ad377c12dc] 流相关的操作函数说明: [code:1:ad377c12dc] close(2) Close a stream ioctl(2) Control a stream getmsg(2) Receive a message at the stream head open(2) Open a stream pipe(2) Create a channel that provides a communication path between multiple processes poll(2) Notify the application program when selected events occur on a stream putmsg(2) Send a message down a stream read(2) Read data from a stream write(2) Write data to a stream Note that applications compiled with the SCO OpenServer Development System must define _SVID3 in the source in order to use the following ioctl commands: I_ATMARK I_CANPUT I_CKBAND I_FLUSHBAND I_GETBAND I_GETCLTIME I_GWROPT I_LIST I_PLINK I_PUNLINK I_SETCLTIME I_SWROPT [/code:1:ad377c12dc] sco流兼容性建议 [code:1:ad377c12dc] I_GETCLTIME compatibility notes This ioctl returns the close time delay in a long on UnixWare 7 and SCO UnixWare 2.1.X; on SCO OpenServer it is returned in an int. I_RECVFD source compatibility notes The uid and gid members of the strrecvfd structure are defined as uid_t and gid_t (that is, long) on UnixWare 7 and SCO UnixWare 2.1.X; on SCO OpenServer they are both defined as an unsigned short. I_S_RECVFD source compatibility notes This ioctl command is unsupported on SCO OpenServer without the UnixWare 7 Binary Compatibility Module for SCO OpenServer installed. I_SETSIG source compatibility notes For the S_BANDBURG event subcommand, UnixWare 7 and SCO UnixWare 2.1.X return SIGURG, while SCO OpenServer returns SIGUSR1. [/code:1:ad377c12dc] 在此感谢各位! 蓝色键盘 |
stevenyi 回复于:2003-07-08 15:01:20 |
谢谢蓝色键盘的资料!
SCO 5.0.6上socketpair试不成功,你试成功了吗? 改用进程池后会收到SIGPOLL信号,不知什么原因?我现在简单的忽略该信号,有更好的处理方法吗? |
m4a1 回复于:2003-07-10 00:07:07 |
socketpair我一直都没试成功过?不过键盘找到SPX,非常感谢 |
蓝色键盘 回复于:2003-07-10 10:08:14 |
[quote:a159a76e07="stevenyi"]谢谢蓝色键盘的资料!
SCO 5.0.6上socketpair试不成功,你试成功了吗? 改用进程池后会收到SIGPOLL信号,不知什么原因?我现在简单的忽略该信号,有更好的处理方法吗?[/quote:a159a76e07] 使用socketpair的时候,简单的创建是不行的 使用poll可能会把问题搞的根复杂,但是poll的好处是描述字集处理起来不想select一样存在莫名其妙的返回。 但是还是建议使用select。 |
m4a1 回复于:2003-07-10 12:00:43 |
键盘兄,socketpair在SCO下到底怎用啊? |
蓝色键盘 回复于:2003-07-10 12:32:29 |
soketpair参看steven网络编程。
上面详细介绍了,总不能遇到问题就要代码,呵呵。 |
m4a1 回复于:2003-07-10 12:44:38 |
代码我知道怎么写。还是报BAD FILE NUBER。HP下没问题 |
bigfu 回复于:2003-07-10 18:52:50 |
我觉得还是 ioctl 来得简单,多谢键盘!! |
蓝色键盘 回复于:2003-07-10 19:08:08 |
是的,ioctl在SCO上面的实现算是比较省事的方式,但是对于SCO来说,最简单的是accept+lock的方式。
对于sendmsg和getmsg来说,存在历史上的兼容性问题,不过比较容易解决,方法可以参看unix环境高级编程或者unix网络编程卷一。 |
stevenyi 回复于:2003-07-10 20:15:36 |
但是ioctl在hp和aix上都不能成功 |
bigfu 回复于:2003-07-11 09:27:17 |
键盘可以说说“最简单的是accept+lock的方式”如何做的吗 |
gadfly 回复于:2003-07-11 14:22:37 |
这个在steve的aup中也有很详细的说明和示例代码。
利用锁(文件锁,信号锁,线程锁互斥锁),保证同时只有一个线程或进程accept listenfd |
蓝色键盘 回复于:2003-07-11 16:27:50 |
嗯。gadfly所说及时。accept+lock。把那个代码简单的更改一下,就可以用了。
源代码可以到网上去找,如果找不到,偶找找贴上来。 |
bigfu 回复于:2003-07-12 13:38:39 |
哦,又长了一些见识 |