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

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的套接字则是一个错误。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏张善友的专栏

Mix 10 上的asp.net mvc 2的相关Session

Beyond File | New Company: From Cheesy Sample to Social Platform Scott Hansel...

2597
来自专栏张善友的专栏

LINQ via C# 系列文章

LINQ via C# Recently I am giving a series of talk on LINQ. the name “LINQ via C...

2665
来自专栏跟着阿笨一起玩NET

c#实现打印功能

2812
来自专栏闻道于事

js登录滑动验证,不滑动无法登陆

js的判断这里是根据滑块的位置进行判断,应该是用一个flag判断 <%@ page language="java" contentType="text/html...

6988
来自专栏张善友的专栏

Silverlight + Model-View-ViewModel (MVVM)

     早在2005年,John Gossman写了一篇关于Model-View-ViewModel模式的博文,这种模式被他所在的微软的项目组用来创建Expr...

2988
来自专栏C#

DotNet加密方式解析--非对称加密

    新年新气象,也希望新年可以挣大钱。不管今年年底会不会跟去年一样,满怀抱负却又壮志未酬。(不过没事,我已为各位卜上一卦,卦象显示各位都能挣钱...)...

4928
来自专栏我和未来有约会

Kit 3D 更新

Kit3D is a 3D graphics engine written for Microsoft Silverlight. Kit3D was inita...

2586
来自专栏java 成神之路

使用 NIO 实现 echo 服务器

4737
来自专栏一个会写诗的程序员的博客

Spring Reactor 项目核心库Reactor Core

Non-Blocking Reactive Streams Foundation for the JVM both implementing a Reactiv...

2192
来自专栏大内老A

The .NET of Tomorrow

Ed Charbeneau(http://developer.telerik.com/featured/the-net-of-tomorrow/) Exciti...

32010

扫码关注云+社区