回射服务器程序
#include "unp.h"
void str_echo(int sockfd)
{
ssize_t n;
char buf[MAXLINE];
again:
while ( (n = read(sockfd, buf, MAXLINE)) > 0)
Writen(sockfd, buf, n);
if (n < 0 && errno == EINTR)
goto again;
else if (n < 0)
err_sys("str_echo: read error");
}
include "unp.h"
int main(int argc, char **argv)
{
int listenfd, connfd;
pid_t childpid;
socklen_t clilen;
struct sockaddr_in cliaddr, servaddr;
listenfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
Listen(listenfd, LISTENQ);
for ( ; ; ) {
clilen = sizeof(cliaddr);
connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);
if ( (childpid = Fork()) == 0) { /* child process */
Close(listenfd); /* close listening socket */
str_echo(connfd); /* process the request */
exit(0);
}
Close(connfd); /* parent closes connected socket */
}
}
回射客户端程序
#include "unp.h"
void str_cli(FILE *fp, int sockfd)
{
char sendline[MAXLINE], recvline[MAXLINE];
while (Fgets(sendline, MAXLINE, fp) != NULL) {
Writen(sockfd, sendline, strlen(sendline));
if (Readline(sockfd, recvline, MAXLINE) == 0)
err_quit("str_cli: server terminated prematurely");
Fputs(recvline, stdout);
}
}
include "unp.h"
int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
if (argc != 2)
err_quit("usage: tcpcli <IPaddress>");
sockfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
Connect(sockfd, (SA *) &servaddr, sizeof(servaddr));
str_cli(stdin, sockfd); /* do it all */
exit(0);
}
正常建立(三次握手)、正常终止(四次挥手)
进程终止之僵死进程
服务器子进程终止时,给父进程发送SIGCHLD信号,服务器进程中没有捕获该信号,而该信号的默认行为是被忽略,因此子进程进入僵死状态。
解决方法:Unix信号处理
POSIX信号处理
信号
信号:“一个进程 或者 内核 ” 告知另一个进程发生了某个事件的通知,也称软件中断。
行为
每个信号都有与之关联的处置,也称行为。可以通过sigaction来设定一个信号的处置:
(1)提供一个函数,每当特定信号发生它就被调用。这种函数称为信号处理函数,这种行为称为捕获信号。SIGKILL和SIGSTOP两种信号不能被捕获。
信号处理函数只有信号值一个参数,没有返回值:
void handler(int signo);
(2)把某个信号的处置设置为SIGIGN来忽略。SIGKILL和SIGSTOP两种信号不能被忽略。
(3)把某个信号的处置设置为SIGDFL来启用它的默认。SIGCHLD和SIDURG两个信号的默认为忽略。