高级C与网络编程复习(5)—— TCP C/S程序示例(TCP

2020-04-26  本文已影响0人  SunnyQjm

简单回射程序概述

TCP 回射服务程序

tcpserv01.c

#include <unp.h>

void str_echo(int);

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

    listenfd = Socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(9748);

    //指定服务端socket的地址为通配地址
    //表示接收来自本机各个网络接口的连接请求
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

    Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
    Listen(listenfd, LISTENQ);

    for( ; ; ){
        clen = sizeof(cliaddr);
        connfd = Accept(listenfd, (SA *) &cliaddr, &clen);
        //接受到来自客户端的请求之后,fork一个进程,在子进程中为客户提供服务
        //父进程则关闭本进程内该已连接描述符(引用计数减1)
        //然后再返回继续accept,可以达到并发的效果
        if( (pid = Fork()) == 0 ){      //子进程执行
            Close(listenfd);
            str_echo(connfd);
            Close(connfd);
            exit(0);
        }
        Close(connfd);                  //父进程执行
    }
}


/**
 * 为客户端提供服务
 * 从客户端接收一个字符串,并将字符串回射回客户端
 */
void str_echo(int connfd){
    ssize_t n;
    char buf[MAXLINE];

again:
    while((n = read(connfd, buf, MAXLINE)) > 0)
        Writen(connfd, buf, n);
    if(n < 0 && errno == EINTR)
        goto again;
    else if(n < 0)
        err_sys("str_echo: read error");
}

TCP 回射客户端程序

#include <unp.h>

void str_cli(FILE*, int);

int main(int argc, char** argv){
    int sockfd;
    struct sockaddr_in servaddr;

    if(argc != 2)
        err_quit("usage: ./tcpserv01 <IPAddress>");
    sockfd = Socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_port = htons(9748);
    servaddr.sin_family = AF_INET;

    //调用inet_pton函数将用户输入的点分十进制串转化成网络字节序的32为IPv4地址
    Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);

    Connect(sockfd, (SA *) &servaddr, sizeof(servaddr));

    str_cli(stdin, sockfd);
    Close(sockfd);
}

/**
 * 用fgets读取用户的一行输入,发送给服务器,再从服务器接收一行回复并打印到控制台
 */
void str_cli(FILE* fp, int sockfd){
    char sendbuf[MAXLINE], recvline[MAXLINE];
    while(Fgets(sendbuf, MAXLINE, fp) != NULL){
        Writen(sockfd, sendbuf, strlen(sendbuf));
        if(Readline(sockfd, recvline, MAXLINE) == 0)
            err_quit("str_cli: server terminated prematurely");
        Fputs(recvline, stdout);
    }
}

正常启动

正常终止

./tcpcli01 127.0.0.1
hello
hello         //服务器回射回来的
good bye
good bye      //服务器回射回来的
^D            //Ctrl + D 相当于输入EOF

//在客户端程序退出后马上查看端口状态(由于是本机测试,一定要快,要不然抓不到)
netstat -a | grep 9748
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 0.0.0.0:9748            0.0.0.0:*               LISTEN
tcp        0      0 localhost:33146         localhost:9748          TIME_WAIT

POSIX 信号处理

信号(signal)就是告知某个进程发生了某个事件的通知,有时也称为软件中断(software interrupt)。通常是异步的

  • 每个信号关联一个处置(deposition),或称行为(action)。在信号发生时执行

处理 SIGCHLD 信号

wait 和 waitpid 函数

#include <sys/wait.h>

/**
* 用于在父进程中清理已终止子进程(解除子进程的僵死状态)
*
* @param  wait函数通过这个参数返回子进程的终止状态
* @return 成功则返回被清理子进程的ID,错误则返回0或-1
*/
pid_t wait(int *statloc);

/**
* 用于在父进程中清理已终止子进程(解除子进程的僵死状态)
* @param pid      用于指定清理那个子进程,如果传入-1则表示等待第一个终止的子进程
* @param statloc  函数通过这个参数返回子进程的终止状态
* @param options  可选项
* @return 成功则返回被清理子进程的ID,错误则返回0或-1
*/
pid_t waitpid(pid_t pid, int *statloc, int options);
上一篇下一篇

猜你喜欢

热点阅读