求助!!accept問題

我用多線程資源管理器,處理其中的accpet事件,accept事件成功返回,
但是使用accept返回值進行後續的read、wirte操作都失敗,錯誤是Bad file descriptor。
這說明accept返回的connection是無效的??
看了accept的代碼,返回的是
fd2 = ConnectAttach(info.nd, info.pid, info.chid, 0, _NTO_COF_CLOEXEC)

ConnectAttach對_NTO_COF_CLOEXEC這個標誌位的解釋是
如果process使用了exec*()創建一個新的process,就會close掉這個connection。

這裡的process是指調用accept的process還是資源管理器的process?
我的代碼也並沒有使用exec*()創建新的process啊,
connection怎么就無效了。。

望高手指導下,謝謝啊!!!!

应该跟accept()的实现没什么关系,把你的代码post出来看看?

int my_io_openfd(resmgr_context_t *ctp, io_openfd_t *msg, RESMGR_OCB_T *ocb)
{
	int listen_fd;
	int child_fd;
	int len;
	struct sockaddr_in *addr;

	switch (msg->i.xtype) {
	case _IO_OPENFD_ACCEPT:
		listen_fd = lookup_listen_fd(msg->i.info.pid,msg->i.info.coid);
		if (listen_fd < 0) {
			printf("can't find listen fd for connect:%d,pid:%d\n", msg->i.info.coid,msg->i.info.pid);
			return _RESMGR_ERRNO(EBADF);
		}
		len = ctp->msg_max_size - ((char *)msg - (char *)ctp->msg);
		addr    = (struct sockaddr_in *)msg;
		iofunc_attr_unlock(ocb->attr);
		child_fd = my_accept(listen_fd, addr, &len);
		iofunc_attr_lock(ocb->attr);
		map_connection_fd(ctp->info.pid,ctp->info.coid, child_fd);
		_RESMGR_STATUS(ctp, len);
		return _RESMGR_ERRNO(0);
		break;
	}
	return _RESMGR_ERRNO(EINVAL);
}

我是将自已的句柄与pid、coid进行映射的。
my_accept里会有sem等待请求。这个可以成功,返回新的fd.
我把pid,coid打印出来也都是和用户进程的pid及accept返回值是一样。
但是用户进程使用accept出来的值进行send、recv等操作都是返回EBADF。
而且都没有跑进去我的_IO_READ\WRITE消息处理函数。。因此判断是这个connection已经被关闭了。。

实在想不出办法。。

啊,你是要实现一个accept的服务器端。

先问个问题,你的服务器端有”io_open"的callout吗?

之所以这样问,是因为 io_openfd()的处理与别的iofunc有些特殊的地方。它其实更像open()与dup()的复合处理。

这个从客户端想一下,比较容易想通。accept()(或者openfd())的结果就是给出一个fd1,得到另一个fd2,而fd2是要同fd1指向同一个文件的。

所以,你的io_openfd()函数,虽然也处理了查找原fd的工作(lookup_listen_fd),但你对于新的连接,没有做"open()"应该做的那些事。如果你写过io_open()的调用,就知道,对于一个新的open(),还需要建立新的ocb,并将它与新的open()挂到一起(iofunc_ocb_attach()).

你的问题是针对新的fd,你并没有分配ocb,这样,客户端在用新的fd进行recv/send时,资源管理器的框架就会因为找不到ocb而出错返回,而不会进入你的io_read/io_write函数。

不知道这样解释是使你更清楚了,还是更糊涂了。呵呵。

作为修改,我建议你在listen_fd判断成功后,做一个iofunc_openfd()调用,好象这样:

      listen_fd = lookup_listen_fd(msg->i.info.pid,msg->i.info.coid);
      if (listen_fd < 0) {
         printf("can't find listen fd for connect:%d,pid:%d\n", msg->i.info.coid,msg->i.info.pid);
         return _RESMGR_ERRNO(EBADF);
      } 
      ret = iofunc_openfd(ctp, msg, ocb, ocb->attr);
      if (ret != EOK) {
          return _RESMGR_ERRNO(ret);
      }

如果你用的都是标准的资源管理器处理的话,这个应该可以。如果你是比如有自己的io_open(),在每个open()时都要自己做一些特殊处理地的话,那么就不能简单地调用iofunc_openfd(),而是必须自己做一个ocb出来,并iofunc_ocb_attach()它。

非常感谢您的热心帮助啊!!
我是想用资源管理器自己实现一个tcp/udp的socket,就像qnx系统里的io-pkt-v4那样。

比如上次的阻塞问题。不知道io-pkt-v4是不是也用多线程资源管理器?
我在qnx系统上做实验,创建多个监听进程进行accept操作,io-pkt-v4并没有生成多个线程,似乎是单线程处理啊。。
不晓得io-pkt-v4单线程的话是怎么在accept上挂起的(sys_accept里使用tsleep挂起)又能处理新的socket请求?

要实现这个东西光靠着Writing a Resource Manager(6.4).pdf 这个资源远远不够啊。。

请问您有关于qnx资源管理器更详细的资料推荐下吗?

还有accept出来的句柄该如何关闭?
现在关闭后,原来listen的句柄操作就会出问题。。
我的关闭操作my_io_close只会解除pid,cid与句柄的关联,并删除该句柄对应的数据结构。
是否还需要其它操作?
加上iofunc_close_dup(ctp, msg, ocb, ocb->attr);还是不行。。

好多问题啊。:slight_smile:

资源管理器除了你说的那个正式文档外,别的有帮助的就是找几个简单的资源管理器的源码来看看了。

io-pkt-v4 是个很复杂的服务器,基本上它是个单线程的服务器,不过在特定情况下(比如多核)它会自动变成多线程。

即使单线程的服务器,也是可以挂起客户端的。客户端accept(),服务器端在ocb里做个记号,记住rcvid,然后return _RESMGR_NOREPLY。这样,下层就不会MsgReply(),客户端就被挂在那里了。服务器端依然可以接受别的请求,进行处理。然后,在accept()联接成功后,服务器端可以再扫描ocb,找到对应的ocb后,MsgReply()客户端就可以了。

当然,这是一般的情况。io-pkt-v4的tsleep()有些特殊。

如果客户端关闭accept()出来的句柄,你就应在io_close_ocb()中进行处理。理论上就是在io_openfd()里为新句柄添加的resource,都要在这里清除掉。