2012-04-11 131 views
1

我有一個監聽TCP unix域/本地套接字的服務器守護進程。運行在同一臺計算機上的多個客戶端連接到它。守護進程也綁定到UDP Internet套接字。只要守護進程從本地客戶端接收到任何數據,它就會向除連接客戶端以外的所有連接客戶端發送相同的數據。如果守護進程接收到UDP因特網套接字上的數據,則需要將該數據發送給所有本地連接的客戶端。當守護程序在本地套接字上接收到數據時,數據的發送/接收工作就完美了。但是,當服務器發送它們在UDP互聯網套接字上接收到的數據時,客戶端不會收到任何數據。客戶端在退出服務器守護程序並關閉連接後,或者在任何客戶端將數據本地發送到服務器時接收該互聯網數據。互聯網數據與客戶端一起接收本地數據。我使用fcntl()將本地和inet套接字設置爲阻塞。下面是我(我已刪除所有不必要的代碼)的守護進程代碼:套接字recv()沒有收到數據

while(1) 
{ 
    FD_SET(sockfd, &read_fds); 
    FD_SET(inet_sock, &read_fds); 
    for (i = 0; i < nclients; i++) 
    { 
    FD_SET(clients[i], &read_fds); 
    } 

    select(maxfd + 1, &read_fds, &write_fds, &except_fds, NULL); 

    /* Check for events on inet sock */ 
    if (FD_ISSET(inet_sock, &read_fds)) 
    { 
    /* Read from inet sock */ 
    socklen = sizeof(dest_sin); 
    rval = recvfrom(inet_sock, buf, BUFLEN-1, MSG_DONTWAIT, 
        (struct sockaddr *) &dest_sin, &socklen);   
    buf[rval]=0; 
    fprintf(stderr, "Received: %d (%d) bytes containing %s", rval, strlen(buf), buf); 

    /* Send the message to every other client */ 
    for(j=0; j < nclients; j++) 
    { 
     send(clients[j], buf, strlen(buf), MSG_DONTWAIT); 
    } 
    } 

    /* A read event on the local socket is a new connection */ 
    if (FD_ISSET(sockfd, &read_fds)) 
    { 
    socklen = sizeof(dest_sun); 
    /* Accept the new connection */ 
    rval = accept(sockfd, (struct sockaddr *) &dest_sun, &socklen); 

    /* Add client to list of clients */ 
    clients[nclients++] = rval; 
    if (rval > maxfd) maxfd = rval; 
    snprintf(s, BUFLEN, "You are client %d [%d]. You are now connected.\n\0", 
     nclients, rval); 
    send(rval, s, strnlen(s, BUFLEN), MSG_DONTWAIT); 
    } 

    /* Check for events from each client */ 
    for (i = 0; i < nclients; i++) 
    { 
    fprintf(stderr,"Checking client %d [%d] for read indicator.\n",i, clients[i]); 

    /* Client read events */ 
    if (FD_ISSET(clients[i], &read_fds)) 
    { 
     fprintf(stderr, "Client %d [%d] marked for read.\n", i, clients[i]); 

     /* Read from client */ 
     rval=recv(clients[i], buf, BUFLEN-1, MSG_DONTWAIT); 

     buf[rval]=0; 
     fprintf(stderr, "Received: %d (%d) bytes containing %s", rval, strlen(buf), buf); 

     /* Send the message to every other client */ 
     for(j=0; j < nclients; j++) 
     { 
     /* Skip the sender */ 
     if (j == i) continue; 
     /* Send the message */ 
     send(clients[j], s, strlen(s, BUFLEN), MSG_DONTWAIT); 
     } 
    } 
    } 
} 

這裏是我的客戶端代碼:

while(1) 
{ 
    FD_SET(fileno(stdin), &read_fds); 
    FD_SET(sockfd, &read_fds); 
    select(fileno(stdin) > sockfd ? fileno(stdin)+1 : sockfd+1, 
&read_fds, &write_fds, &except_fds, NULL); 

    if (FD_ISSET(sockfd, &read_fds)) 
    { 
    /* Read from socket and display to user */ 
    mlen = recv(sockfd, (void *)buf, BUFLEN-1, MSG_DONTWAIT); 
    buf[mlen]=0; 
    printf("Received %d bytes: %s", mlen, buf); 
    } 

    if (FD_ISSET(fileno(stdin), &read_fds)) 
    { 
    fgets(buf, BUFLEN, stdin); 
    fprintf(stderr, "Sent %d octets to server.", 
    send(sockfd, (void *)buf, (size_t) strnlen(buf, BUFLEN), 0)); 
    } 
} 

的目標是讓客戶端接收數據守護進程立即發送它們(守護進程在其inet套接字上收到的數據)。編輯:我已經計算出,當守護進程發送數據時,客戶端的select()返回該套接字可讀,但recv()阻塞,這就是我沒有獲取數據的原因客戶端。對於如何解決這個問題,有任何的建議嗎?

+0

雖然沒有東西跳出來,但請不要在formf()語句中發送send()。另外,你說你刪除了代碼。實際工作示例是否檢查返回碼/ errno? – Duck 2012-04-11 01:06:47

+0

是的,實際的程序會進行錯誤檢查。 – ddd 2012-04-11 01:43:49

+0

跳到我身上的是你永遠不會檢查send和recv調用的返回值。另外,如何在服務器和客戶端創建UDP套接字? – 2012-04-11 07:11:51

回答

1

下面是你的代碼,提取和比對的send()電話:

send(clients[j], buf, strlen(buf),  MSG_DONTWAIT); 
send(rval,  s, strnlen(s, BUFLEN), MSG_DONTWAIT); 
send(clients[j], s, strlen(s, BUFLEN), MSG_DONTWAIT); 

我在這裏看到了一些不一致的地方。有時你會撥打strlen(),有時strnlen(),有時候會有strlen()兩個參數(我甚至不知道該怎麼辦)。

您所看到的問題可能與以下事實有關:您未在套接字上發送任何顯示消息之間邊界的信息。在流套接字上,消息邊界是而不是被保留,您應該注意在協議中包含適當的幀信息,以便接收方可以提取單個消息。您不能完全通過recv()呼叫來獲得完全相同的字節數,因爲呼叫中存在send()。您將得到相同順序的合計字節數(這是流套接字的一點),但是這些消息可能會整合或分裂,並且您無法控制該數據。

相關問題