2012-05-16 101 views
2

我在服務器端爲使用C的聊天客戶端編寫了下面的代碼。但是,在while循環中,我需要檢查客戶端是否已退出程序,即與客戶端的連接是否丟失。請告訴我如何編寫這樣的代碼。如何檢查服務器端是否建立了連接C

#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <errno.h> 
#include <string.h> 
#include <time.h> 
int main() 
{ 
int sock, connected, bytes_recieved , true = 1, pid; 
char send_data [1024] , recv_data[1024];  
struct sockaddr_in server_addr,client_addr;  
int sin_size; 
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
{ 
    perror("Socket"); 
    exit(1); 
} 
if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(int)) == -1) 
{ 
    perror("Setsockopt"); 
    exit(1); 
} 
server_addr.sin_family = AF_INET;   
server_addr.sin_port = htons(3128);  
server_addr.sin_addr.s_addr = INADDR_ANY; 
bzero(&(server_addr.sin_zero),8); 
if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) 
{ 
    perror("Unable to bind"); 
    exit(1); 
} 
if (listen(sock, 5) == -1) 
{ 
    perror("Listen"); 
    exit(1); 
} 
printf("\nTCPServer Waiting for client on port 3128"); 
fflush(stdout); 
FILE *log; 
log = fopen("time.log", "a"); 
time_t t; 
while(1) 
{ 
    sin_size = sizeof(struct sockaddr_in); 
    connected = accept(sock, (struct sockaddr *)&client_addr,&sin_size); 
    printf("\n I got a connection from (%s , %d)", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); 
    fflush(stdout);   
    int pid=fork(); 
    while(1) 
    {  
     if(pid == 0) 
     { 
      usleep(1000000); 
      time(&t); 
      send(connected, ctime(&t),30, 0); 
     } 
     else 
     { 
      bytes_recieved = recv(connected,recv_data,1024,0); 
      recv_data[bytes_recieved] = '\0'; 
      fputs(recv_data, log); 
      fputs("Time: ", log); 
      time(&t); 
      fputs(ctime(&t), log); 
     } 
     fflush(log); 
    } 
    } 
fclose(log); 
close(sock); 
return 0; 
} 

請幫忙。

現在我修改這樣的代碼:

while(1) 
{  
    if(pid == 0) 
    { 
     usleep(1000000); 
     time(&t); 
     send(connected, ctime(&t),30, 0); 
    } 
    else 
    { 
     bytes_recieved = recv(connected,recv_data,1024,0); 
     recv_data[bytes_recieved] = '\0'; 
     fputs(recv_data, log); 
     fputs("Time: ", log); 
     time(&t); 
     fputs(ctime(&t), log); 
    } 
    fflush(stdout); 
    fflush(log); 
    fclose(log); 
    if(bytes_recieved == 0 || bytes_recieved == -1) 
    { 
     close(sock); goto connct;} 
    } 
} 
close(sock); 
return 0; 

在編譯時,它會很好,但上運行,它提供了以下錯誤的輸出:

*** glibc detected *** ./server: double free or corruption (!prev): 0x09936008 *** 
======= Backtrace: ========= 
/lib/i686/cmov/libc.so.6(+0x6b381)[0xb7659381] 
/lib/i686/cmov/libc.so.6(+0x6cbd8)[0xb765abd8] 
/lib/i686/cmov/libc.so.6(cfree+0x6d)[0xb765dcbd] 
/lib/i686/cmov/libc.so.6(fclose+0x14a)[0xb764982a] 
./server[0x8048c21] 
/lib/i686/cmov/libc.so.6(__libc_start_main+0xe6)[0xb7604ca6] 
./server[0x8048861] 
======= Memory map: ======== 
08048000-08049000 r-xp 00000000 08:01 133298  /home/harikrishnan/server/server 
08049000-0804a000 rw-p 00000000 08:01 133298  /home/harikrishnan/server/server 
09936000-09957000 rw-p 00000000 00:00 0   [heap] 
b7400000-b7421000 rw-p 00000000 00:00 0 
b7421000-b7500000 ---p 00000000 00:00 0 
b75bf000-b75dc000 r-xp 00000000 08:01 3653635 /lib/libgcc_s.so.1 
b75dc000-b75dd000 rw-p 0001c000 08:01 3653635 /lib/libgcc_s.so.1 
b75ed000-b75ee000 rw-p 00000000 00:00 0 
b75ee000-b772e000 r-xp 00000000 08:01 3670051 /lib/i686/cmov/libc-2.11.3.so 
b772e000-b772f000 ---p 00140000 08:01 3670051 /lib/i686/cmov/libc-2.11.3.so 
b772f000-b7731000 r--p 00140000 08:01 3670051 /lib/i686/cmov/libc-2.11.3.so 
b7731000-b7732000 rw-p 00142000 08:01 3670051 /lib/i686/cmov/libc-2.11.3.so 
b7732000-b7735000 rw-p 00000000 00:00 0 
b7744000-b7747000 rw-p 00000000 00:00 0 
b7747000-b7748000 r-xp 00000000 00:00 0   [vdso] 
b7748000-b7763000 r-xp 00000000 08:01 3654097 /lib/ld-2.11.3.so 
b7763000-b7764000 r--p 0001b000 08:01 3654097 /lib/ld-2.11.3.so 
b7764000-b7765000 rw-p 0001c000 08:01 3654097 /lib/ld-2.11.3.so 
bfd94000-bfda9000 rw-p 00000000 00:00 0   [stack] 
*** glibc detected *** ./server: double free or corruption (!prev): 0x09936008 *** 
======= Backtrace: ========= 
/lib/i686/cmov/libc.so.6(+0x6b381)[0xb7659381] 
/lib/i686/cmov/libc.so.6(+0x6cbd8)[0xb765abd8] 
/lib/i686/cmov/libc.so.6(cfree+0x6d)[0xb765dcbd] 
/lib/i686/cmov/libc.so.6(fclose+0x14a)[0xb764982a] 
./server[0x8048c21] 
/lib/i686/cmov/libc.so.6(__libc_start_main+0xe6)[0xb7604ca6] 
./server[0x8048861] 
======= Memory map: ======== 
08048000-08049000 r-xp 00000000 08:01 133298  /home/harikrishnan/server/server 
08049000-0804a000 rw-p 00000000 08:01 133298  /home/harikrishnan/server/server 
09936000-09957000 rw-p 00000000 00:00 0   [heap] 
b7400000-b7421000 rw-p 00000000 00:00 0 
b7421000-b7500000 ---p 00000000 00:00 0 
b75bf000-b75dc000 r-xp 00000000 08:01 3653635 /lib/libgcc_s.so.1 
b75dc000-b75dd000 rw-p 0001c000 08:01 3653635 /lib/libgcc_s.so.1 
b75ed000-b75ee000 rw-p 00000000 00:00 0 
b75ee000-b772e000 r-xp 00000000 08:01 3670051 /lib/i686/cmov/libc-2.11.3.so 
b772e000-b772f000 ---p 00140000 08:01 3670051 /lib/i686/cmov/libc-2.11.3.so 
b772f000-b7731000 r--p 00140000 08:01 3670051 /lib/i686/cmov/libc-2.11.3.so 
b7731000-b7732000 rw-p 00142000 08:01 3670051 /lib/i686/cmov/libc-2.11.3.so 
b7732000-b7735000 rw-p 00000000 00:00 0 
b7744000-b7747000 rw-p 00000000 00:00 0 
b7747000-b7748000 r-xp 00000000 00:00 0   [vdso] 
b7748000-b7763000 r-xp 00000000 08:01 3654097 /lib/ld-2.11.3.so 
b7763000-b7764000 r--p 0001b000 08:01 3654097 /lib/ld-2.11.3.so 
b7764000-b7765000 rw-p 0001c000 08:01 3654097 /lib/ld-2.11.3.so 
bfd94000-bfda9000 rw-p 00000000 00:00 0   [stack] 
Aborted 

任何想法的實際問題是什麼?

+0

您需要[select()](http://linux.die.net/man/2/select)等待輸入,關閉事件等。 – Rup

+0

您在每次迭代時都記錄(記錄)。只有第一個可以成功。 – wildplasser

回答

0

如果發送返回SOCKET_ERROR這意味着關閉套接字或連接丟失

所以只是做

if (send(connected, ctime(&t),30, 0) == SOCKET_ERROR) 
{ 
    // blablabla 
} 
+0

'server.c:80:error:'SOCKET_ERROR'未聲明(首次在此函數中使用)'這是編譯上述代碼時出現的錯誤。 – binish

+1

@JohnSmith:SOCKET_ERROR沒有在linux上定義,所以檢查應該是'if(send()== -1)',然後評估錯誤的'errno'。 – dwalter

+0

對不起,我看到了標籤...>< –

3

recv()將盡快在客戶端關閉了連接返回0。如果在嘗試從套接字獲取數據時出現任何錯誤,將返回-1

參見man page瞭解更多信息。

所以更改您的代碼

int conn_closed = 0; 

    bytes_recieved = recv(connected,recv_data,1024,0); 
    switch (bytes_recieved) { 
    case 0: 
     /* connection closed by client */ 
     close(connected); 
     conn_closed = 1; 
     break; 
    case -1: 
     /* error on socket */ 
     /* TODO: insert error handling code */ 
     if (errno == EAGAIN || errno == EINTR) { 
      /* safe to retry */ 
      conn_closed = 0; 
     } else { 
      close(connected) 
      conn_closed = 1; 
     } 
     break; 
    default: 
     recv_data[bytes_recieved] = '\0'; 
     fputs(recv_data, log); 
     fputs("Time: ", log); 
     time(&t); 
     fputs(ctime(&t), log); 
     conn_closed = 0; 
     break; 
    } 
    /* break out of the loop if conn_closed */ 
    if (conn_closed) 
     break; 

,不要忘記檢查的send()的返回值,看是否在發送數據時發生錯誤。

更新:增加了錯誤處理代碼EAGAINEINTR

月2日更新:

爲了完整起見,這裏是你應該添加發送

if (send(connected, ctime(&t),30, 0) == -1) 
{ 
    if (errno == EAGAIN || errno == EINTR) { 
     /* retry to send */ 
    } 
    close(connected); 
    break; 
} 
+3

我不認爲這個開關真的需要。如果上面的代碼將正常工作,那麼將會如下: int conn_closed; bytes_recieved = recv(connected,recv_data,1024,0); 如果(bytes_recieved == 0 || bytes_recieved == -1){ // 聲明 } –

+0

順便說一句,你可能還需要關閉出錯的插座,不只是斷開 – Hasturkun

+0

你應該處理的'的返回值-1',並檢查「errno」,因爲它可能是您剛剛被信號中斷的情況,並且可以安全地重試。這就是我選擇switch()的原因。 – dwalter

0

一個小小的建議你的情況,而不是給一個「如果」條件檢查連接的代碼,在'while'中做同樣的事情,而不是'while(1)',給出條件。

相關問題