您的位置:首页 > 其它

NetworkIPC之初识Client-Server实验部分(五)

2018-03-12 21:52 253 查看

1. 题目

1.1 题目二

In the program in Figure 16.18, the server waits for the child to execute the uptime command and exit before accepting the next connect request. Redesign the server so that the time to service one request doesn’t delay the processing of incoming connect requests.

1.2 题目三

Write two library routines: one to enable asynchronous (signal-based) I/O on a socket and one to disable asynchronous I/O on a socket. Use Figure 16.23 to make sure that the functions work on all platforms with as many socket types as possible.



2. 分析

2.1 题目二

  题目二中的原代码如下所示,其每次调用
accpet
之后会
fork
一个新的进程,将新进程的标准输入输出重导向到建立连接的socket上,先不说这样做的弊端,在父进程里面调用
waitpid
,阻塞了新连接的建立。所以问题的关键就是获取子进程结束信息,又不阻塞父进程。

//另外一种serve函数
void serve(int sockfd)
{
int clfd, status;
pid_t pid;
set_cloexec(sockfd);
for (;;) {
if ((clfd = accept(sockfd, NULL, NULL)) < 0) {
syslog(LOG_ERR, "ruptimed: accept error: %s",
strerror(errno));
exit(1);
}
if ((pid = fork()) < 0) {
syslog(LOG_ERR, "ruptimed: fork error: %s",
strerror(errno));
exit(1);
} else if (pid == 0) { /* child */
/*
* The parent called daemonize, so
* STDIN_FILENO, STDOUT_FILENO, and STDERR_FILENO
* are already open to /dev/null. Thus, the call to
* close doesn’t need to be protected by checks that
* clfd isn’t already equal to one of these values.
*/
if (dup2(clfd, STDOUT_FILENO) != STDOUT_FILENO || dup2(clfd, STDERR_FILENO) != STDERR_FILENO) {
syslog(LOG_ERR, "ruptimed: unexpected error");
exit(1);
}
close(clfd);
//将标准输出和标准错误重新定向到clfd,之后调用execl
execl("/usr/bin/uptime", "uptime", (char *)0);
syslog(LOG_ERR, "ruptimed: unexpected return from exec: %s", strerror(errno));
} else { /* parent */
//每次的都需要等待子进程执行完uptime,注意这点
close(clfd);
waitpid(pid, &status, 0);
}
}
}


2.2 题目三

  这里的异步IO准确的说应该是信号驱动的IO,使用
fcntl
或者
ioctl
都可以达成目的。

3. 代码展示

3.1 代码一

int main(void)
{
....
if(signal(SIGCHLD,sig_chld) == SIG_ERR)
handle_error("signal");
....
}

void sig_chld(int signo)
{
pid_t pid;
int stat;
while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0)
printf("child %d terminated\n", pid);
return;
}

void serve(int sockfd)
{
int clfd, status;
pid_t pid;
set_cloexec(sockfd);
for (;;) {
if ((clfd = accept(sockfd, NULL, NULL)) < 0) {
syslog(LOG_ERR, "ruptimed: accept error: %s",
strerror(errno));
exit(1);
}
if ((pid = fork()) < 0) {
syslog(LOG_ERR, "ruptimed: fork error: %s",
strerror(errno));
exit(1);
} else if (pid == 0) { /* child */
/*
* The parent called daemonize, so
* STDIN_FILENO, STDOUT_FILENO, and STDERR_FILENO
* are already open to /dev/null. Thus, the call to
* close doesn’t need to be protected by checks that
* clfd isn’t already equal to one of these values.
*/
if (dup2(clfd, STDOUT_FILENO) != STDOUT_FILENO || dup2(clfd, STDERR_FILENO) != STDERR_FILENO) {
syslog(LOG_ERR, "ruptimed: unexpected error");
exit(1);
}
close(clfd);
//将标准输出和标准错误重新定向到clfd,之后调用execl
execl("/usr/bin/uptime", "uptime", (char *)0);
syslog(LOG_ERR, "ruptimed: unexpected return from exec: %s", strerror(errno));
} else { /* parent */
//每次的都需要等待子进程执行完uptime,注意这点
close(clfd);
//删除waitpid
}
}
}


3.2 代码二

int set_sig_recv(int sockfd)
{
if(fcntl(sockfd,F_SETOWN,getpid()) == -1)
{
syslog(LOG_ERR, "fcntl %s", strerror(errno)););
exit(1);
}
return 0;
}
int enable_sio(int sockfd)
{
int status;
if((status = fcntl(sockfd,F_GETFD)) == -1)
{
syslog(LOG_ERR, "fcntl %s", strerror(errno)););
exit(1);
}
if(fcntl(fd, F_SETFL, status|O_ASYNC) == -1)
{
syslog(LOG_ERR, "fcntl %s", strerror(errno)););
exit(1);
}

}
int disable_sio(int sockfd)
{
int status;
if((status = fcntl(sockfd,F_GETFD)) == -1)
{
syslog(LOG_ERR, "fcntl %s", strerror(errno)););
exit(1);
}
if(fcntl(fd, F_SETFL, status&(~O_ASYNC)) == -1)
{
syslog(LOG_ERR, "fcntl %s", strerror(errno)););
exit(1);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: