UNIX网络编程第5章TCP客户服务器程序示例5.2 5.3 5.4 5.5 5.6 5.7

_QT)SRO6`C]DGX0S[0[ZC6G

 

5AA[2DAH}~TKJ)62R7VHJMK

 

H6@K7~VW((7JYE~(E[8`_RJ

 

#include <iostream>
#include "../lib/unpsunyj.h"

int main(int argc, char** argv)
{
    int                listenfd;
    int                connfd;
    pid_t              childpid;
    socklen_t          clilen;
    struct sockaddr_in cliaddr;
    struct sockaddr_in servaddr;

    // listenfd = Socket(AF_INET, SOCK_STREAM, 0);
    if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        err_sys("socket error");

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family      = AF_INET; // 如果是多宿,我们将接受目的地址为任何本地接口的连接
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    std::cout << SERV_PORT << std::endl;
    servaddr.sin_port        = htons(SERV_PORT);

    // Bind(listenfd, (SA*)&servaddr, sizeof(servaddr));
    if (bind(listenfd, (sockaddr*)&servaddr, sizeof(servaddr)) < 0)
    {
        err_sys("bind error");
    }

    // Listen(listenfd, LISTENQ); // 转换为监听套接字
    if (listen(listenfd, LISTENQ) < 0)
    {
        err_sys("listen error");
    }

    for ( ; ; )
    {
        clilen = sizeof(cliaddr);
        // connfd = Accept(listenfd, (SA *) &cliaddr, &len);
again:
        if ((connfd = accept(listenfd, (sockaddr*)&cliaddr, &clilen)) < 0)
        {
#ifdef  EPROTO
            if (errno == EPROTO || errno == ECONNABORTED)
#else
                if (errno == ECONNABORTED)
#endif
                    goto again;
                else
                    err_sys("accept error");
        }

        // clilen = sizeof(cliaddr);
        // 服务器阻塞于accept调用,等待客户连接的完成
        // connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);
        // fork为每个客户派生一个处理它们的子进程,子关闭监听套接字,父关闭已连接套接字
        if ((childpid = fork()) == -1)
            err_sys("fork error");
        if (0 == childpid) /* child process */
        {
            // Close(listenfd);    /* close listening socket */
            if (close(listenfd) == -1)
            {
                err_sys("close error");
            }
            str_echo(connfd);   /* process the request */
            std::cout << "exiting tcpserv01 child process" << std::endl;
            // 服务器子进程调用exit来终止。服务器子进程中打开的所有描述符随之关闭,
            // 这会导致TCP连接终止序列
            // 的最后两个分节:一个从服务器到客户的FIN,和,一个从客户到服务器的ACK,至此,
            // 连接完全终止,客户套结字进入TIME_WAIT状态。

            // 另一方面
            // when this child is existed, this process will send sigchild signal to parent process
            // and in the parent process, we did not handle this signal, so the child process,
            // this process will be a zombie process, we can see that by command ps ux
            // exit(0);
            return 0;
        }
        // Close(connfd); /* parent closes connected socket */
        if (close(connfd) == -1)
        {
            err_sys("close error");
        }
    }
}

 

Z[G1P4I@}$3NO4%WPRKF04O

 

T`NP9GVI96]125A[`7[QJRA

 

ZYPQ9((3PT]K7KNON3_$Q`H

 

#include <iostream>
#include "unpsunyj.h"

// 从客户读入数据,并把数据回射给客户
void str_echo(int sockfd)
{
    ssize_t n;
    char    buf[MAXLINE];

again:
    while ( (n = read(sockfd, buf, MAXLINE)) > 0) // 从套接字读入数据
        Writen(sockfd, buf, n);                   // 把其中内容回射给客户。如果客户关闭连接(这是正常情况),那么接收到客户的FIN将导致服务器子进程的read函数返回0
    // 这又导致str_echo函数的返回,从而在tcpserv01.c中终止子进程。

    if (n < 0 && errno == EINTR)
        goto again;
    else if (n < 0)
        err_sys("str_echo: read error");

    std::cout << "exiting str_echo" << std::endl;
}

 

)~[T]D%HX`]JO[FYL5Q8J0A

RM3%RIH8_@HOF_(BQ$K[(GX

 

)_(}]]G$Y[83FGGIN587`_1

 

#include <iostream>
#include "../lib/unpsunyj.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);
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        err_sys("socket error");
    }

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(SERV_PORT);
    // Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
    if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
    {
        err_quit("inet_pton error for %s", argv[1]);
    }

    // Connect(sockfd, (SA *) &servaddr, sizeof(servaddr));
    if (connect(sockfd, (sockaddr*)&servaddr, sizeof(servaddr)) < 0)
    {
        err_sys("connect error");
    }

    str_cli(stdin, sockfd); /* do it all */

    std::cout << "exiting tcpcli01 main" << std::endl;
    // when a program is exiting, part of this action is that 
    // the kernal will close all descriptors opened,
    // including all the sockets.
    // 1, the client tcp(this program) will send FIN to server(tcpserv),
    // 2, the server tcp send ack to respond, then the server socket will be in CLOSE_WAIT status
    //    客户端套结字则处于FIN_WAIT_2状态
    // 3, 当服务器TCP接收FIN时,服务器子进程阻塞于readline调用,于是readline返回0,这导致
    //    str_echo函数返回服务器子进程的main函数
    // 4,服务器子进程调用exit来终止。服务器子进程中打开的所有描述符随之关闭,这会导致TCP连接终止序列
    //    的最后两个分节:一个从服务器到客户的FIN,和,一个从客户到服务器的ACK,至此,
    //    连接完全终止,客户套结字进入TIME_WAIT状态。
    // 
    // so the server will detect that this client is closing.
    exit(0);
}

 

WK]LV``6XZ]BT8))1UNDZ46

 

Y}ZQWUO`TE49OA]J4%SMVVP

 

#include "unpsunyj.h"

void str_cli(FILE *fp, int sockfd)
{
    char sendline[MAXLINE];
    char recvline[MAXLINE];

    // 从标准输入读入一行文本
    // 当遇到文件结束符或错误时,fgets将返回一个空指针,于是客户处理终止循环。我们的Fgets包裹函数检查是否发生错误,若发生则中止进程,因此Fgets只是在遇到文件结束符时
    // 才返回一个空指针
    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);
    }
    Fputs("exiting str_cli\n", stdout);
}

 

R{%~U5CMY3T1YCUJKTZD$K1

 

_TI3]O_[])R%W[)U086[`31

 

W]U[XFT2]5IS579LLARXBNT\

ps -t pts/6 -o pid,ppid,tty,stat,args,wchan

 

V6Y3{ZXWY@R4LD4_3T_X[XR

 

}H7%LR2SRH@%_V6HEVWNY7B

 

 

 

ROSI_004_020

ROSI_004_021ROSI_004_022ROSI_004_023ROSI_004_024ROSI_004_025ROSI_004_026ROSI_004_027ROSI_004_028

ROSI_004_029

ROSI_004_030

ROSI_004_031ROSI_004_032ROSI_004_033ROSI_004_034ROSI_004_035ROSI_004_036

ROSI_004_037

ROSI_004_038

ROSI_004_039ROSI_004_040ROSI_004_041

ROSI_004_042ROSI_004_043ROSI_004_044

ROSI_004_045ROSI_004_046

posted @ 2015-03-16 19:49  孙永杰  阅读(647)  评论(0编辑  收藏  举报