如何避免服务器套接字的TIME_WAIT?

inc*_*cud 5 c sockets linux

我知道你会把它掩盖为重复(问题1,问题2,问题3),但答案不是我正在寻找的(我认为也是其他人).
所以,我指的是socket master(我爱你们):如果我关闭套接字怎么能得到绑定错误(地址已经在使用中)?
我会描述我的问题.

我有一个与服务器 通信的客户端
在服务器中,我有两个套接字:sockS(主套接字,监听)和sockTX(客户端一个)
如果我调用我的程序一次,通信没问题,那么我关闭两个套接字
如果我记得服务器和客户端,我得到错误,我要等待TIME_WAIT(在Ubuntu 32bit上约3分钟)

为什么,在关闭两个套接字之后我仍然会遇到绑定错误?
有一种方法可以使它无任何魔法(SO_REUSEADDR)吗?
我知道我的代码中有些错误...

谢谢大家.

那是代码:
客户端

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

#define PORT 5000
#define SERVER "127.0.0.1"
#define MAXLINE 128

int printMessage(char* str);

int main(){
char buff[MAXLINE+1];

struct sockaddr_in server, client;
struct hostent *host;
int sock, n;
//socklen_t len;

    if((sock = socket(AF_INET,SOCK_STREAM,0)) == -1){
        perror("\nErrore socket()");
        return -1;
    }

    client.sin_family = AF_INET;
    client.sin_port = htons(0); // la porta e' scelta dal sistema operativo
    client.sin_addr.s_addr = htonl(INADDR_ANY);

    if( bind(sock,(struct sockaddr*)&client, sizeof(client)) == -1){
        perror("\nErrore bind()");
        return -1;
    }

    server.sin_family = AF_INET;
    server.sin_port = htons(PORT);

    if((host = gethostbyname(SERVER)) == NULL ){
        perror("\nErrore gethostbyname()");
        return -1;
    }

    server.sin_addr = *((struct in_addr *)host->h_addr);

    if(connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0){
        perror("\nErrore connect");
        return -1;
    }

    // MESSAGGIO

    sprintf(buff, "CTX\nclientTX\nserver\nCiao da client\n");
    if(send(sock, buff, strlen(buff), 0) < 0) {
        perror("\nErrore sendto");
        return -1;
    }
    else {
        printf("\nMessaggio inviato");
    }

    if((n = recv(sock, buff, MAXLINE, 0)) < 0) {
        perror("\nErrore ricezione risposta");
        return -1;
    } else {
        buff[n] = '\0';
        int test = printMessage(buff);
        printf("\nEsito: %s\n", (test == 1 ? "OK" : "FAIL"));
    }

    shutdown(sock, 2); // 2 = RD_WR
    close(sock);
    return 0;
}

int printMessage(char* str){
int i;
char* temp;

    printf("Mittente: ");
    for(i = 0; str[i] != '\n'; i++)
        printf("%c", str[i]);
    printf(" ");
    for(i = i+1; str[i] != '\n'; i++)
        printf("%c", str[i]);
    printf("\nDestinatario: ");
    for(i = i+1; str[i] != '\n'; i++)
        printf("%c", str[i]);

    temp = (char*)malloc(30 * sizeof(char));
    strncpy(temp, str+i+1, 30);
    printf("Messaggio: %s\n", temp);

    if(strcmp(temp, "OK") == 0)
        return 1;
    else
        return 0;
}
Run Code Online (Sandbox Code Playgroud)


服务器:

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

#define PORT 5000
#define SERVER "127.0.0.1"
#define MAXLINE 128

int printMessage(char* str);

int main() {
char buff[MAXLINE+1];
struct sockaddr_in server; //, client;
int sockS, sockTX, n;

    if((sockS = socket(AF_INET,SOCK_STREAM,0)) == -1)
    {
        perror("\nErrore socket()");
        return -1;
    }

    server.sin_family = AF_INET;
    server.sin_port = htons(PORT);
    server.sin_addr.s_addr = htonl(INADDR_ANY);

    if(bind(sockS, (struct sockaddr *)&server, sizeof(server)) == -1)
    {
        perror("\nErrore bind()");
        return -1;
    }

    if(listen(sockS, 10) == -1)
    {
        perror("\nErrore listen()");
        return -1;
    }
    printf("SERVER\nInizializzazione completata!\n");

    if((sockTX = accept(sockS, (struct sockaddr *)NULL, NULL)) == -1)
    {
        perror("\nErrore accept()");
        return -1; 
    }
    printf("Socket connesso\n");

    // INVIO
    if((n = recv(sockTX, buff, MAXLINE, 0)) < 0) {
        perror("\nErrore recv()");
        return -1; // BREAK??

    } else {
        buff[n] = '\0';
        printMessage(buff);

    }

    sprintf(buff, "S\nserver\nclientTX\nOK\n");
    if(send(sockTX, buff, strlen(buff), 0) < 0){
        perror("\nErrore send()");
        return -1; // BREAK??

    } else {
        printf("Risposta inviata\n");

    }

    shutdown(sockTX, 2);
    close(sockTX);

    shutdown(sockS, 2);
    close(sockS);
    return 0;   
}

int printMessage(char* str){
int i;
char* temp;

    printf("Mittente: ");
    for(i = 0; str[i] != '\n'; i++)
        printf("%c", str[i]);
    printf(" ");
    for(i = i+1; str[i] != '\n'; i++)
        printf("%c", str[i]);
    printf("\nDestinatario: ");
    for(i = i+1; str[i] != '\n'; i++)
        printf("%c", str[i]);

    temp = (char*)malloc(30 * sizeof(char));
    strncpy(temp, str+i+1, 30);
    printf("Messaggio: %s\n", temp);

    if(strcmp(temp, "OK\n") == 0)
        return 1;
    else
        return 0;
}
Run Code Online (Sandbox Code Playgroud)

谢谢大家

编辑1:可能的解决方案(不是很漂亮,但只比SOCK_REUSEADDR多一点)
尝试在关闭和关闭两个服务器的套接字之前添加一个sleep(1).
客户端将在服务器之前关闭它将工作
不是很漂亮,我知道.

或者,更好的是,在关闭服务器内的第一个套接字之前,您可以检查客户端是否关闭了连接(如此)

jxh*_*jxh 6

如果您遵循TCP状态机图,您将看到如果套接字启动发送FIN,则套接字必须转换到TIME-WAIT状态.shutdown(sockTX, 2)无需等待客户端的FIN即可正常使用.

如果您希望服务器等待客户端的FIN,则首先阻止recv()等待0返回值.然后,你可以close().

请注意,除非您以某种方式(使用dup*()或通过fork()调用)复制了套接字,否则无需调用shutdown()它,如果它紧跟一个close().您可以只调用close()(如果套接字已被复制,FIN将仅在最后一个副本关闭时发送).

根本不需要shutdown()接受socket(sockS).

所以,我会改变你的服务器端看起来像下面这样清理套接字:

while (recv(sockTX,...) > 0) {}
close(sockTX);

close(sockS);
Run Code Online (Sandbox Code Playgroud)