首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >UNPv13:#第5章#TCP客户/服务器程序示例

UNPv13:#第5章#TCP客户/服务器程序示例

作者头像
_gongluck
发布2018-03-09 14:20:24
6710
发布2018-03-09 14:20:24
举报

Code

github

//server.c

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

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

    return;
}

int main(int argc, char* argv[])
{
    int listenfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(listenfd == -1)
    {
        perror("function socket error :");
        exit(-1);
    }

    struct sockaddr_in serveraddr;
    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serveraddr.sin_port = htons(atoi(argv[1]));
    if(bind(listenfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) == -1)
    {
        perror("function bind error : ");
        exit(-1);
    }

    if(listen(listenfd, 5) == -1)
    {
        perror("function listen error : ");
        exit(-1);
    }

    struct sigaction act, oact;
    act.sa_handler = sig_chld;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    if(sigaction(SIGCHLD, &act, &oact) == -1)
    {
        perror("function sigaction error : ");
        exit(-1);
    }

    int connfd;
    struct sockaddr_in clientaddr;
    socklen_t clientlen;
    while(1)
    {
        clientlen = sizeof(clientaddr);
        connfd = accept(listenfd, (struct sockaddr *)&clientaddr, &clientlen);
        if(connfd == -1)
        {
            if(errno == EINTR)
                continue;
            perror("function accept error : ");
            exit(-1);
        }

        if(fork() == 0)
        {
            if(close(listenfd) == -1)
            {
                perror("function close error : ");
                exit(-1);
            }

            char buf[1024];
            int len;
        AGAIN:
            while((len = read(connfd, buf, 1024)) > 0)
                write(connfd, buf, len);
            if(len < 0 && errno == EINTR)
                goto AGAIN;
            else if(len < 0)
            {
                perror("function read error : ");
                exit(1);
            }
        }
        else
        {
            if(close(connfd) == -1)
            {
                perror("function close error : ");
                exit(-1);
            }
        }
    }
    return 0;
}
//client.c

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc, char* argv[])
{
    int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(sockfd == -1)
    {
        perror("function socket error : ");
        exit(-1);
    }

    struct sockaddr_in serveraddr;
    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    switch(inet_pton(AF_INET, argv[1], &serveraddr.sin_addr))
    {
    case 0:
        perror("function inet_pton error (input invalid) : ");
        exit(-1);
        break;
    case 1:
        //successed
        break;
    default:
        perror("function inet_pton error : ");
        exit(-1);
        break;
    }
    serveraddr.sin_port = htons(atoi(argv[2]));
    connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));

    char buf[1024];
    while(fgets(buf, 1024, stdin) != NULL)
    {
        write(sockfd, buf, strlen(buf));
        if(read(sockfd, buf, 1024) == 0)
        {
            perror("server terminated");
            exit(0);
        }
        fputs(buf, stdout);
    }

    return 0;
}

服务器进程终止

客户TCP收到FIN只是表示服务器进程已关闭连接的服务端,从而不再往其中发送任何数据而已。FIN的接收并没有告知客户TCP服务器进程已经终止。

SIGPIPE信号

当一个进程向某个已收到RST的套接字执行写操作时,内核向该进程发送一个SIGPIPE信号。该信号默认行为是终止进程。不论该进程捕获该信号并从其信号处理函数返回,还是简单的忽略该信号,写操作都将返回EPIPE。 第一次写操作引发RST,第二次写引发SIGPIPE信号。写一个已接收FIN的套接字不成问题,但写一个已接收了RST的套接字则是一个错误。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017年12月19日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Code
  • 服务器进程终止
  • SIGPIPE信号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档