为什么我的服务器和客户端同时出现TIME_WAIT?

时间:2015-12-03 04:05:42

标签: c linux tcpclient tcpserver

我在测试服务器和客户端时遇到了一个奇怪的问题。 服务器和客户端同时显示TIME_WAIT!

这是我的服务器代码:

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

#define LISTEN_QUEUE    20
#define MAX_LINE        1024
#define MAXN            16384

int parse(char *buf)
{
    int num;

    sscanf(buf, "%d", &num);
    return num;
}

int main()
{
    int listenfd, connfd, r, n;
    pid_t childpid;
    socklen_t chilen;
    struct sockaddr_in chiaddr, servaddr;
    char buf[MAX_LINE];
    char content[MAXN];

    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if(listenfd < 0)
        printf("listen socket get error\n"), exit(-1);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(9999);

    r = bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    if(r < 0)
        printf("bind socket error\n"), exit(-1);

    r = listen(listenfd, LISTEN_QUEUE);

    memset(content, 'A', MAXN);
    while(1)
    {
        chilen = sizeof(chiaddr);
        connfd = accept(listenfd, (struct sockaddr *)&chiaddr, &chilen);
        memset(buf, 0, MAX_LINE);
        r = read(connfd, buf, MAX_LINE);
        n = parse(buf);
        write(connfd, content, n);
        close(connfd);
    }
}

这是我的客户代码:

#include <unp.h>

#define MAXN 16384

static int readn(int fd, char *buf, int nbytes)
{
    int nread, ntoread, n;

#ifdef __DEBUG__
    char temp[1024];
#endif /* __DEBUG__ */

    nread = 0;
    ntoread = nbytes;
    while(nread < nbytes)
    {
        n = read(fd, buf, ntoread);
        if(n < 0)
            printf("read nbytes error\n"), exit (-1);
        else if(n == 0)
            break;
        else
        {

#ifdef __DEBUG__
            memcpy(temp, buf, n);
            temp[n] = 0;
            printf("%s\n", temp);
#endif /* _DEBUG__ */

            buf += n;
            nread += n;
            ntoread = nbytes - nread;
        }
    }
    return nread;
}

static int Tcp_connect(char *host, char *port)
{
    struct hostent *h;
    char str[16];       
    struct sockaddr_in addr;

    h = gethostbyname(host);
    addr.sin_family = h->h_addrtype;
    addr.sin_port = htons(atoi(port));
    addr.sin_addr = *(struct in_addr *)(h->h_addr);

#ifdef __DEBUG__
    if(h->h_addrtype == AF_INET)
        printf("AF_INET\n");
    printf("server ip is :%s\n", inet_ntoa(addr.sin_addr));
#endif /* __DEBUG__ */

    int fd = socket(h->h_addrtype, SOCK_STREAM, 0);
    if(fd < 0)
        printf("socket get failed\n"), exit(-1);

#ifdef __DEBUG__
    printf("socket get success\n");
#endif /* __DEBUG__ */

    if(connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
        printf("connect failed\n"), exit(-1);

#ifdef __DEBUG__
    printf("connected success\n");
#endif /* __DEBUG__ */

    return fd;
}

int main(char argc, char *argv[])
{
    int i, j, fd, nchilds, nloops, nbytes;
    pid_t pid;
    ssize_t n, nread;
    char request[MAX_LINE], reply[MAXN];

    if(argc != 6)
        printf("usage : client <IP addr> <port> <#children>
            <#loops/child> <#bytes/request>"), 
        exit(-1);
    nchilds = atoi(argv[3]);
    nloops = atoi(argv[4]);
    nbytes = atoi(argv[5]);
    snprintf(request, sizeof(request), "%d\n", nbytes);

    for(i = 0; i < nchilds; i++)
    {
        if((pid = fork()) == 0) //son
        {
            nread = 0;
            for(j = 0; j < nloops; j++)
            {
//              printf("begin connect\n");
                fd = Tcp_connect(argv[1], argv[2]);
                write(fd, request, strlen(request));
                if((n = readn(fd, reply, nbytes)) != nbytes)
                    printf("server return %d bytes\n", (int)n), exit(-1);
                else
                    nread += n;
                close(fd);
            }
            printf("child %d done, read total %d bytes\n", i, (int)nread);
             exit(0);
         }
    }
    while(wait(NULL) > 0) ;
    if(errno != ECHILD)
        printf("wait error\n"), exit(-1);
 }

我在我的机器上运行服务器和客户端。 客户端cmd是

./client 127.0.0.1 9999 5 100 4000

然后我跑

netstat -a | grep 9999 > log

当我跑

grep -c TIME_WAIT log

结果为501,但根据book,结果应为500。 我打开日志,然后在一个连接上同时在TIME_WAIT中找到服务器和客户端

tcp        0      0 localhost:54915         localhost:9999            TIME_WAIT  
tcp        0      0 localhost:9999          localhost:54915         TIME_WAIT  

太奇怪了,我不知道为什么

1 个答案:

答案 0 :(得分:1)

您正在建立和关闭客户端和服务器之间的连接 - 客户端连接到服务器,发送一些数据,从服务器接收响应然后关闭连接。同样,服务器也会在此交换后断开连接。当您关闭客户端和服务器之间的连接时,您正在观察TIME_WAIT状态。

TIME_WAIT状态是正常的TCP连接状态,因为TCP堆栈在FIN交换后不会立即清除TCB。 TIME_WAIT状态表示等待足够的时间传递以确保远程TCP收到其连接终止请求的确认。有关TCP状态机的更多详细信息,请参阅TCP RFC 793。

如果你在端口9999上执行grep,当你的客户端和服务器正在运行时,你会注意到ESTABLISHED状态的连接。

您可以避免在循环中建立和关闭TCP连接,即更改服务器和客户端程序以建立连接,然后进入循环以交换数据。