URN Logo
UNIX Resources » Linux » China Linux Forum » C/C++编程版 » 37 » 为了这个问题都快折腾半个月,郁闷死了!很着急!
announcement 声明: 本页内容为中国Linux论坛的内容镜像,文章的版权以及其他所有的相关权利属于中国Linux论坛和相应文章的作者,如果转载,请注明文章来源及相关版权信息。
Resources
China Linux Forum(finished)
Linux Forum(finished)
FreeBSD China(finished)
linuxforum.net
  业界新闻与评论
  自由软件杂谈
  IT 人生
  Linux软件快递
  翻译作坊
  Linux图书与评论
  GNU Emacs/XEmacs
  Linux 中文环境和中文化
  Linux桌面与办公软件
  Linux 多媒体与娱乐版
  自由之窗Mozilla
  笔记本电脑上的Linux
  Gentoo
  Debian 一族
  网络管理技术
  Linux 安装与入门
  WEB服务器和FTP服务器
  域名服务器和邮件服务器
  Linux防火墙和代理服务器应用
  文件及打印服务器
  技术培训与认证
  Linux内核技术
  Linux 嵌入技术
  Linux设备驱动程序
  Linux 集群技术
  LINUX平台数据库
  系统和网络安全
  CPU 与 编译器
  系统计算研究所专栏
  Linux下的GUI软件开发
  C/C++编程版
  PHP 技 术
  Java&jsp技术
  Shell编程技术
  Perl 编 程
  Python 编 程
  XML/Web Service 技术
  永远的Unix
  FreeBSD世界
   
为了这个问题都快折腾半个月,郁闷死了!很着急!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Subject: 为了这个问题都快折腾半个月,郁闷死了!很着急!
Author: Qiaoxd    Posted: 2005-02-27 00:58    Length: 4,731 byte(s)
[Original] [Print] [Top]
各位老大,怎么没人回答我的问题呀,真的很急,很郁闷。
问题简单的说就是一个网络daemon 程序,通过shell执行一切正常。而通过如下system调用就总是说daemon程序子进程的socketfd 非法, char *cmdline 为daemon程序绝对路径名
int
run_cmd (char *cmdline)
{
int result = SUCCESS, i, max_fd_num;
if (fork () == 0)
{
max_fd_num = getdtablesize ();
for (i = 0; i < max_fd_num; i++)
close (i);
system (cmdline);
exit (0);
}
return result;
}

下面为daemon服务程序中的do_daemon函数
int
do_daemon(int port)
{
struct sockaddr_in sa;
static struct sockaddr_in serv_addr;
int length = sizeof (serv_addr);
int sock, sockl;
pid_t pid;
int boundok = 1;
char reuse = 1;
int devnull;
int cnt;
#ifdef HAVE_SETSID
(void) setsid ();
#endif
if ((pid = fork ()) == -1)
return (-1);
if (pid)
exit (0); /* parent exits */
devnull = open ("/dev/null", O_RDWR, 0);
if (devnull != -1)
{
(void) dup2 (devnull, 0);
(void) dup2 (devnull, 1);
(void) dup2 (devnull, 2);
if (devnull > 2)
(void) close (devnull);
}

sa.sin_family = AF_INET;
bzero ((char *) &sa.sin_addr, sizeof (sa.sin_addr));
sa.sin_port = htons (port);

// to bind proxy with inside interface
if(inside_ip[0])
{
sa.sin_addr.s_addr = inet_addr(inside_ip);
syslog(LOG_INFO,"bind with inside ip : %s:%d",inside_ip,inet_addr(inside_ip));
}

sock = socket (AF_INET, SOCK_STREAM, 0);
if (sock < 0)
{
syslog (LOG_ERR, "Failed to create socket, %m");
exit (1);
}
setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof (reuse));
while (bind (sock, (struct sockaddr *) &sa, sizeof (sa)))
{
syslog (LOG_INFO, "Failed to bind port %d, %m,exit!", port);
syslog (LOG_INFO, "Sleeping for 15 seconds");
//test
// exit(0);
sleep(15);
// boundok = 0;
}
#ifndef SOMAXCONN
#define SOMAXCONN 20
#endif
if (listen (sock, SOMAXCONN) < 0)
{
syslog (LOG_ERR, "Failed to listen, %m");
exit (1);
}
#if 0
if (boundok == 0)
{
syslog (LOG_WARNING, "Now ready on port %d", port);
}
#endif
//信号处理
signal (SIGCHLD, xxxx);

while (1)
{
int cstat;
memset (buffer, 0, 1500);
sockl = accept (sock, (struct sockaddr *) 0, (int *) 0);
if (sockl < 0)
{
if (errno == EINTR)
continue;
syslog (LOG_ERR, "Accept failed, %m");
continue;
}

pid = fork ();
if (pid < 0)
{
syslog (LOG_ERR, "Fork failed, %m");
/* 9/8/95 pjc. Make fork failure non-fatal, just throw connection for now */
close (sockl);
continue;
}
if (pid == 0)
break; /* We are the child */
close (sockl);
}
#ifdef HAVE_SETSID
(void) setsid ();
#endif
close (0);
close (1);
close (2);
dup (sockl);
dup (sockl);
dup (sockl);
close (sockl);
close (sock);
}

显然这里把子进程连接套接字重定向到0,可是在子进程调用
getsockname (0, (struct sockaddr *) &serv_addr, &length)时总是报Bad file descriptor.
但是通过shell命令行启动daemon则无问题。
真是急死人了,为这问题都快忙活半个月,郁闷死了
[Original] [Print] [Top]
Subject: Re: 为了这个问题都快折腾半个月,郁闷死了!很着急!
Author: Atu    Posted: 2005-02-28 09:45    Length: 297 byte(s)
[Original] [Print] [Top]
如果你能动源码,就自己调试一下

在出错的 getsockname 之前,加一个暂停指令,
如getchar()之类的,或干脆加一个长延时

然后,在暂停的时候到/proc/pid_of_your_procs/fd/目录下,看
是否有0这个文件描述符

然后再进一步调试。
[Original] [Print] [Top]
Subject: Re: 为了这个问题都快折腾半个月,郁闷死了!很着急!
Author: Qiaoxd    Posted: 2005-02-28 13:33    Length: 610 byte(s)
[Original] [Print] [Top]
谢谢,但可能不行。因为自动执行是通过另外一个类似思科ios的shell发出的,该shell没有查看/proc目录的功能,退回到bash才能看到。但也可能在daemon执行时用其它用户登陆到bash就可以看到了。
我有一个想法就是通过bash命令行执行时,没有关闭0、1、2;而通过一楼中run_cmd函数自动执行时,该函数先关闭了所有打开的文件描述符,问题是不是出在这里呢?
另外再提供一个情况就是如果先在bash手动启动该daemon,再进入专用shell再次自动启动同一daemon时,问题虽然没有了,但所有发给console的日志信息全发到client端了,注意子进程的连接套接字为0。
怎么解释这一现象呢,好象发生了关于“0”的混乱。
期盼大家的答复!
[Original] [Print] [Top]
Subject: Re: 为了这个问题都快折腾半个月,郁闷死了!很着急!
Author: Atu    Posted: 2005-02-28 14:14    Length: 418 byte(s)
[Original] [Print] [Top]
>但也可能在daemon执行时用其它用户登陆到bash就可以看到了。
这一点你说的对。

确实可能是文件描述符的问题。
我觉得你还是想办法动态调试效果会好一些,
至少比静态分析代码要容易。

这个问题如果可以重现的话,应该很容易解决。
既然你能动它的源码,你就可以在它dup的时候,加一些print指令,
打印出一些必要数据,然后再观察。

[Original] [Print] [Top]
Subject: Re: 为了这个问题都快折腾半个月,郁闷死了!很着急!
Author: Qiaoxd    Posted: 2005-02-28 23:02    Length: 397 byte(s)
[Original] [Print] [Top]
问题是每次出现,目前我的调试方法也仅限于用syslog函数做日志。
如何实现动态调试,我没用过。是用gdb吗?
我现在特别想知道为什么命令行启动,程序就不出错;而利用run_cmd函数(在一楼)就错;
run_cmd函数看来也没错,因为用它启动其它两个网络服务也一切正常。其它两个daemon的daemon化过程与一楼的do_daemon函数非常类似,只是出问题的daemon 程序添加了父进程和子进程之间的信号灯和共享内存。
[Original] [Print] [Top]
Subject: Re: 为了这个问题都快折腾半个月,郁闷死了!很着急!
Author: Atu    Posted: 2005-03-02 09:38    Length: 283 byte(s)
[Original] [Print] [Top]
> 如何实现动态调试,我没用过。是用gdb吗?

在程序运行时,打印或log出你所关心的变量,数据,函数的参数,返回值等;
我觉得你这种情况不需要用gdb.

是否父子进程共享文件描述符和socket过程中出了问题?

多试试吧
[Original] [Print] [Top]
Subject: Re: 为了这个问题都快折腾半个月,郁闷死了!很着急!
Author: xihoujin    Posted: 2005-03-03 17:33    Length: 130 byte(s)
[Original] [Print] [Top]
运行时,可动态查看/proc/pid/fd 下面的"数字"文件是不是增长的...
如果不断增大,就该考虑那里没有close 文件描述符了..
[Original] [Print] [Top]
Subject: Re: 为了这个问题都快折腾半个月,郁闷死了!很着急!
Author: beatit    Posted: 2005-03-03 23:27    Length: 73 byte(s)
[Original] [Print] [Top]
应该不是什么大问题,建议在do_daemon中把setsid放在fork调用之后,慢慢调吧!
[Original] [Print] [Top]
Subject: Re: 为了这个问题都快折腾半个月,郁闷死了!很着急!
Author: Qiaoxd    Posted: 2005-03-10 23:42    Length: 362 byte(s)
[Original] [Print] [Top]
我也怀疑是父进程和子进程共享的文件描述符及socket出错了,但问题的关键是为什么直接通过命令行执行就没错而用run_cmd调用就出现子进程socket错误呢(注意,命令行执行与run_cmd的区别,前者似乎没有关闭0、1、2,而后者先fork然后在子进程关闭所有文件描述符)。
另外这段do_daemon函数改自fwtk的do_daemon,set_id的调用顺序原来就如此,利用该函数实现的其它程序没有任何问题。
[Original] [Print] [Top]
Subject: Re: 为了这个问题都快折腾半个月,郁闷死了!很着急!
Author: Qiaoxd    Posted: 2005-03-19 23:00    Length: 369 byte(s)
[Original] [Print] [Top]
关于上述问题的最新进展是,在run_cmd()函数调用该网络daemon后,不再报子进程Bad file descriptor的错误了,而且日志也表明此时子进程连接套接字正常,但是奇怪的是仍然不能正常实现网络代理功能,该在console显示的日志信息却通过上述套接字通过网络传过来(抓包看到的),很是困惑!
再次提醒一下该网络代理daemon通过命令行直接手工启动,则一切正常。恳请得到大家的帮助!
[Original] [Print] [Top]
Subject: Re: 为了这个问题都快折腾半个月,郁闷死了!很着急!
Author: Qiaoxd    Posted: 2005-03-26 22:48    Length: 82 byte(s)
[Original] [Print] [Top]
恳请大家继续关注这个问题,问题仍然没有解决啊,老板限期10个工作日解决,真是着急啊!
[Original] [Print] [Top]
Subject: Re: 为了这个问题都快折腾半个月,郁闷死了!很着急!
Author: zm1979    Posted: 2005-03-29 10:17    Length: 80 byte(s)
[Original] [Print] [Top]
你先将文件描述符给关了再进行fork调用。以前好像有的问题就是这样解决的!你试一下吧
----
水人一个
[Original] [Print] [Top]
Subject: Re: 为了这个问题都快折腾半个月,郁闷死了!很着急!
Author: daemonq    Posted: 2005-03-29 15:39    Length: 602 byte(s)
[Original] [Print] [Top]

close (0);
close (1);
close (2);
dup (sockl);
dup (sockl);
dup (sockl);
改成
dup2(sock1,0);
dup2(sock1,1);
dup2(sock1,2);
试试
另外,加点判断,看看下面的open 和dup2有没有成功:
devnull = open ("/dev/null", O_RDWR, 0);
if (devnull != -1)
{
(void) dup2 (devnull, 0);
(void) dup2 (devnull, 1);
(void) dup2 (devnull, 2);
if (devnull > 2)
(void) close (devnull);
}
[Original] [Print] [Top]
Subject: Re: 为了这个问题都快折腾半个月,郁闷死了!很着急!
Author: Qiaoxd    Posted: 2005-03-29 23:48    Length: 86 byte(s)
[Original] [Print] [Top]
谢谢,问题初步解决了,我用system函数直接调用,问题就不再出现了。但原因仍然不十分清楚。
[Original] [Print] [Top]
« Previous thread
怎样才能在configure文件中添加自己定义的参数?
C/C++编程版
37
Next thread »
子进程的执行过程?
     

Copyright © 2007 UNIX Resources Network, All Rights Reserved.      About URN | Privacy & Legal | Help | Contact us
备案序号: 京ICP备05006143    webmaster: webmaster@unixresources.net
This page created on 2008-07-17 03:53:09, cost 0.065652847290039 ms.