2

私のコードは次のとおりです。

int main(int argc, char *argv[])
{
    int sockfd, new_fd;  /* listen on sock_fd, new connection on new_fd */
    struct sockaddr_in my_addr;    /* my address information */
    struct sockaddr_in their_addr; /* connector's address information */
    socklen_t sin_size;

    /* generate the socket */
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }

    /* generate the end point */
    my_addr.sin_family = AF_INET;         /* host byte order */
    my_addr.sin_port = htons(MYPORT);     /* short, network byte order */
    my_addr.sin_addr.s_addr = INADDR_ANY; /* auto-fill with my IP */
        /* bzero(&(my_addr.sin_zero), 8);   ZJL*/     /* zero the rest of the struct */

    /* bind the socket to the end point */
    if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) \
    == -1) {
        perror("bind");
        exit(1);
    }

    /* start listnening */
    if (listen(sockfd, BACKLOG) == -1) {
        perror("listen");
        exit(1);
    }

    printf("server starts listnening %d...\n",sockfd);

    /* repeat: accept, send, close the connection */
    /* for every accepted connection, use a sepetate process or thread to serve it */
while(1) {  /* main accept() loop */
    sin_size = sizeof(struct sockaddr_in);
    if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, \
    &sin_size)) == -1) {
        perror("accept");
        continue;
    }
    printf("server: got connection from %s\n", \
        inet_ntoa(their_addr.sin_addr));

    if ((numbytes=recv(new_fd, buf, MAXDATASIZE, 0)) == -1) {
    perror("recv");
    exit(1);
    }

    buf[numbytes] = '\0';

    printf("Received: %s",buf);

    if (send(new_fd, "Hello, world!\n", MAXDATASIZE, 0) == -1)
        perror("send");
        close(new_fd);
        exit(0);

    close(new_fd);  /* parent doesn't need this */

    while(waitpid(-1,NULL,WNOHANG) > 0); /* clean up child processes */
}
return 0;
}

したがって、このサーバーを実行するたびに、1 つのクライアントがそれを使用した後に終了します。しかし、もう一度実行したい場合は、60 秒以内に言うbind: Address already in useと、「close() 関数が実際にソケットを解放して、すぐに再び使用できるようになると思いました」というエラーが表示されます。それで、私はここで何が欠けていますか?

4

4 に答える 4

8

を呼び出す前に、ソケット オプションbindを使用して、アドレス/ポートを再利用する可能性があることをマークできます。SO_REUSEADDR

int reuseaddr = 1;
int err = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
                     &reuseaddr, sizeof(reuseaddr));
于 2012-10-24T00:32:36.213 に答える
0

遅延はTIME_WAITによるものです

接続を終了するプロセスで覚えておくべき重要なことは、接続の両側のアプリケーションプロセスが、接続の半分を個別に閉じる必要があるということです。TCP接続のスリーウェイハンドシェイクポリシーにより、カーネルは反対側の接続も閉じられているという確認応答を待ちます

ただし、次の方法でこの機能をオーバーライドできます。

方法1

/etc/sysctl.confファイルに、次の行を追加して、再起動後も保持します。

net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1

方法2

echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle
echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse
于 2013-03-13T18:53:37.180 に答える
0

まず、このコードの元の形式はBeej's guideから来ています

非常に間違っているか、簡潔にするために編集されたコードを提供しました。「Hello World」応答を送信した後、exit(0) を呼び出します。中括弧を追加してください。

if (send(new_fd, "Hello, world!\n", MAXDATASIZE, 0) == -1)
    perror("send");
    close(new_fd);
    exit(0);

Beej; のコード:

    if (!fork()) { // this is the child process
        close(sockfd); // child doesn't need the listener
        if (send(new_fd, "Hello, world!", 13, 0) == -1)
            perror("send");
        close(new_fd);
        exit(0);
    }
    close(new_fd);  // parent doesn't need this`

また、Beej のコードとあなたのコードは、クライアントによって接続が失われたか中止された場合に「recv」が 0 を返すイベントを処理しないことを指摘してもよろしいですか。ちなみに、recv の呼び出しはブロックされることを覚えておいてください。

if ((numbytes=recv(new_fd, buf, MAXDATASIZE, 0)) == -1) {
perror("recv");
exit(1);
}

これはおそらくクラッシュには影響しないように見えますが、クライアントが予期せず閉じられたときに、この特定の問題が原因で予期しないクラッシュが発生する可能性があります。

于 2012-10-25T06:29:20.843 に答える
0

また、listen() 呼び出しで使用する BACKLOG が定義されている場所もわかりません。これがたまたま 1 に設定されている場合は、それを増やすことができます。次に、最後のソケットが閉じている間、次の呼び出しを処理できます。

于 2012-10-24T01:28:24.167 に答える