LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1138|回复: 9

TCP回射服务器疑问

[复制链接]
发表于 2007-7-17 17:07:05 | 显示全部楼层 |阅读模式
写了一个简单的TCP回射服务器,功能是将客户端的输入原样返回给客户端,类似命令echo。
服务器作为daemon进程运行,并捕捉SIGCHLD信号防止僵死。

出现的问题是:当多个客户端连接服务器的时候,最后一个客户端退出时,服务器也同时退出了,不知道是怎么回事,希望大虾们给与帮助,谢谢。

源程序见附件

源程序说明:
服务器: gcc echotcpsrv.c safe_rw.c str_echo.c signal.c daemon.c -o echotcpsrv
客户端: gcc echotcpcli.c safe_rw.c str_cli.c -o echotcpcli

另外编译服务器程序的时候会有一个警告:
echotcpsrv.c:25: warning: passing arg 1 of `daemon_init' makes integer from pointer without a cast
我查了源文件没有发现问题,并且我在另一台机器上编译时没有报这样的警告,这又是怎么回事呢?

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
发表于 2007-7-18 22:40:14 | 显示全部楼层
首先一处错误
echotcpsrv.c中将

  1. extern int daemon_init(const char, int);
复制代码

改为

  1. extern int daemon_init(const char*, int);
复制代码

其次是既然都作为精灵进程了,怎么还用printf和perror啊,应该用syslog啊,不然你干嘛openlog,这样的话,你就会发现当有一个客户端断开时,accept会返回EINTR,说明父进程被SIG_CHLD中断了,所以就退出了,有两种办法可以解决:
可以在设置信号处理函数设置SA_RESTART标志,如:

  1. act.sa_flags |= SA_RESTART;
复制代码

或者使用goto语句,如:

  1. again:
  2.         if ( (connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &len)) < 0) {
  3.             syslog(LOG_ERR, "accept error: %m");
  4.             if (errno == EINTR)
  5.                     goto again;
复制代码

当然推荐使用前一种

PS:建议写代码千万别偷懒,尽量多加一些错误处理,不然很难定位错误
回复 支持 反对

使用道具 举报

 楼主| 发表于 2007-7-19 09:52:01 | 显示全部楼层
非常感谢你的帮助和建议,程序已经修改好了。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2007-7-19 09:57:18 | 显示全部楼层
之前没有写成daemon的形式,是后来加上去的,所以就忘了改成syslog,多谢wawxdyy兄的指点。
回复 支持 反对

使用道具 举报

发表于 2007-7-19 17:39:24 | 显示全部楼层
别客气,大家互相帮助
回复 支持 反对

使用道具 举报

发表于 2007-7-19 19:58:36 | 显示全部楼层
你好,我想请教一下,act.sa_flags |= SA_RESTART;是设置这个信号中断处理是重启刚才的系统调用, 但是我在看<UNIX网络编程>这本书的时候, 上面5.9节说到当我们编写捕获信号的程序时, 必须对慢系统调用返回EINT有所准备. 即使某个实现 支持SA_RESTART标志, 也并非所有的被中断的系统调用都可以自动重启.
所以我觉得你刚才说的第二种方法是可行的, 但是第一种方法会不会不太完全可靠? 我个人认为应该将两个合在一起或者用第二个, 你认为呢?
另外再请教一下, 如果将两个合在一起了, 那么如果我的系统调用是允许重启的, 那么在信号处理之后就不会执行到errno==EINTR这一步而是就直接继续执行accept()调用吗?望指教.
回复 支持 反对

使用道具 举报

发表于 2007-7-19 20:07:43 | 显示全部楼层
如果系统调用是允许重启的, 不论是自己设置其为可以重启还是系统本身提供, 那么在产生信号时内核将重启被中断的系统调用, 于是accept不会返回错误, 而是继续执行.
如果不允许重启, 那么accept就产生错误, 同时检查当前错误类型, EINTR表示是由于信号的错误, 所以又返回继续执行了.
回复 支持 反对

使用道具 举报

 楼主| 发表于 2007-7-19 20:10:53 | 显示全部楼层
我认为第二种方法是一定行的,第一种要依赖于系统实现,在我的系统中(slackware 12)这两种方式都是可行的。

另外,我觉得EINTR错误的返回也是依赖于系统的,我的系统中会有这样的错误返回,只要会返回这样的错误,那么系统应该是总会设置这个错误到errno的,因为这个错误是一个进程捕获到某个信号且相应信号的处理函数返回时产生的,而不和你是否设置了flags标志相关吧。

我是这么理解的,不知道对不对,大家共同讨论吧。

p.s. 我也正在看《unix网络编程》这本书,希望能共同学习和讨论,共同进步。
回复 支持 反对

使用道具 举报

发表于 2007-7-19 20:15:47 | 显示全部楼层
Post by ratcj
我认为第二种方法是一定行的,第一种要依赖于系统实现,在我的系统中(slackware 12)这两种方式都是可行的。

另外,我觉得EINTR错误的返回也是依赖于系统的,我的系统中会有这样的错误返回,只要会返回这样的错误,那么系统应该是总会设置这个错误到errno的,因为这个错误是一个进程捕获到某个信号且相应信号的处理函数返回时产生的,而不和你是否设置了flags标志相关吧。

我是这么理解的,不知道对不对,大家共同讨论吧。

p.s. 我也正在看《unix网络编程》这本书,希望能共同学习和讨论,共同进步。



嗯.是的.返回的errno与设置flags应该没有关系.
errno是系统调用出错返回之后的错误码. 而flags是设置对于这个信号所采取的执行方法, 例如是否重启被中断的进程.
回复 支持 反对

使用道具 举报

 楼主| 发表于 2007-7-19 20:29:28 | 显示全部楼层
嗯,多谢scutan的肯定,以后还请多多帮助。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表