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

时间:2021-12-02 17:51:42

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

 

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

 

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

 

#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");
        }
    }
}

 

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

 

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

 

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

 

#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;
}

 

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

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

 

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

 

#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);
}

 

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

 

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

 

#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);
}

 

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

 

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

 

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

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

 

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

 

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

 

 

 

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

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

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

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

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

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

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

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

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

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