2015-09-20 58 views
-1

我想使用此套接字打開連接,Fork它並保持打開狀態,直到我或客戶端程序終止連接。無法獲取套接字以保持活動狀態並接收數據

目前我只能打開它,然後收到一條消息,然後關閉,或者保持打開狀態,但不能檢索任何數據,原因我不知道。

下面的代碼主要是教程,但最終我試圖讓while循環讀取select函數,直到消息準備好被讀取。然後,我只是希望它在收到該字符串時不打印該字符串。

我一直在搞這個代碼,我真的很累,所以很抱歉,如果我搞砸了。

有沒有一種方法可以使我創建的Fork函數有一個while(1)循環,只需檢查接收消息的套接字?

void *socket_handler_thread(void *x_void_ptr) 
{ 
    int sockfd, new_fd; // listen on sock_fd, new connection on new_fd 
    struct addrinfo hints, *servinfo, *p; 
    struct sockaddr_storage their_addr; // connector's address information 
    socklen_t sin_size; 
    struct sigaction sa; 
    int yes = 1; 
    char s[INET6_ADDRSTRLEN]; 
    int rv; 

    memset(&hints, 0, sizeof hints); 
    hints.ai_family = AF_UNSPEC; 
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_flags = AI_PASSIVE; // use my IP 

    if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) 
    { 
    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); 

    } 

// loop through all the results and bind to the first we can 
    for (p = servinfo; p != NULL; p = p->ai_next) 
    { 
    if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) 
    { 
     perror("server: socket"); 
     continue; 
    } 

    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) 
    { 
     perror("setsockopt"); 
     exit(1); 
    } 

    if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) 
    { 
     close(sockfd); 
     perror("server: bind"); 
     continue; 
    } 

    break; 
    } 

    freeaddrinfo(servinfo); // all done with this structure 

    if (p == NULL) 
    { 
    fprintf(stderr, "server: failed to bind\n"); 
    exit(1); 
    } 

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

    sa.sa_handler = sigchld_handler; // reap all dead processes 
    sigemptyset(&sa.sa_mask); 
    sa.sa_flags = SA_RESTART; 
    if (sigaction(SIGCHLD, &sa, NULL) == -1) 
    { 
    perror("sigaction"); 
    exit(1); 
    } 

    printf("server: waiting for connections...\n"); 

    int socket_fd, result; 
    fd_set readset; 
    struct timeval tv; 
    /* Wait up to five seconds. */ 
    tv.tv_sec = 0; 
    tv.tv_usec = 100000; 

    while (1) 
    { // main accept() loop 
    sin_size = sizeof their_addr; 
    new_fd = accept(sockfd, (struct sockaddr *) &their_addr, &sin_size); 

    if (new_fd == -1) 
    { 
     perror("accept"); 
     continue; 
    } 

    inet_ntop(their_addr.ss_family, 
     get_in_addr((struct sockaddr *) &their_addr), s, sizeof s); 
    printf("server: got connection from %s\n", s); 

    do 
    { 

     FD_ZERO(&readset); 
     FD_SET(new_fd, &readset); 
     result = select(new_fd + 1, &readset, NULL, NULL, &tv); 
     printf("Stuck result = %i ::: new_fd = %i \n\r", result, new_fd); 
    } while (result == -1 && errno == EINTR); 

    if (result > 0) 
    { 
     if (FD_ISSET(new_fd, &readset)) 
     { 
     if (!fork()) 
     { // this is the child process 

      printf("WORKED!"); 

      Fork(sockfd, new_fd); 

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

     result = recv(socket_fd, some_buffer, some_length, 0); 
     if (result == 0) 
     { 
     /* This means the other side closed the socket */ 
     //close(socket_fd); 
     } 
     else 
     { 
     /* I leave this part to your own implementation */ 
     } 

    } 
    else if (result < 0) 
    { 
     printf("Connection closed!"); 
     /* An error ocurred, just print it to stdout */ 
    } 
    } 

} 

void Fork(int sockfd, int new_fd) 
{ 
    int n; 
    char buffer[256]; 
    bzero(buffer, 256); 

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

    n = read(new_fd, buffer, 255); 
    if (n > 0) 
    { 
    printf("NOW-> %i ::: %s", n, buffer); 
    } 

    close(new_fd); 
    exit(0); 
} 
+0

**哪些**教程? –

+0

C是區分大小寫的,所以'fork'不是'fork'不是'FORK'。您的命名非常混亂。 –

+0

正確格式並縮進你的代碼!這個爛攤子是不可讀的。也是更具體的,並提供一個[mcve] – Olaf

回答

-1

保持插座連接打開:

使用setsockopt的()函數與 '存活' 選項

#include <sys/socket.h> 

int setsockopt(int socket, int level, int option_name, 
    const void *option_value, socklen_t option_len); 

SO_KEEPALIVE 
Keeps connections active by enabling the periodic transmission of messages, if this is supported by the protocol. 
This option takes an int value. 

Return Value 

Upon successful completion, setsockopt() shall return 0. Otherwise, -1 shall be returned and errno set to indicate the error. 

這裏是這裏一個例子

int on = 1; 
if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) < 0) 
{ // then setsockopt failed 
    perror("setsockopt failed for SO_KEEPALIVE"); 
    exit(EXIT_FAILURE); 
} 

被來自:http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html的報價關於保持活動setsockopt()

開始報價: 「2.4。防止由於網絡不活動而導致的斷開 Keepalive的另一個有用目標是防止不活動斷開通道。這是一個非常普遍的問題,當你在NAT代理或防火牆後面時,沒有理由斷開連接。此行爲是由代理和防火牆中實施的連接跟蹤過程引起的,這些跟蹤過程跟蹤通過它們的所有連接。由於這些機器的物理限制,他們只能在內存中保留有限數量的連接。最常見和合乎邏輯的策略是保持最新的連接並首先丟棄舊的和不活動的連接。 返回到Peers A和B,重新連接它們。通道一旦打開,請等到事件發生,然後將此通知給其他對等方。如果事件經過很長一段時間驗證會怎麼樣?我們的連接有其範圍,但代理服務器是未知的。所以當我們最終發送數據時,代理無法正確處理它,並且連接斷開。 因爲正常的實現將連接放在列表頂部,當它的一個數據包到達時,並且當它需要消除一個條目時選擇隊列中的最後一個連接,通過網絡週期性地發送數據包是永遠處於一個極小的風險刪除的極地位置。 「 結束報價:

+0

這根本沒有幫助OP。 – alk

+0

@alk,OP詢問如何保持連接/套接字打開。 SO_KEEPALIVE恰恰是*保持套接字在幾個'消息'中打開的方法。 – user3629249

+0

在「正常」情況下,如果發送者或接收者明確地關閉它或關閉它,則無論數據是否通過它發送,TCP套接字連接都將被關閉。 http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html – alk

相關問題