2010-07-30 204 views
2

從我從this thread得到的答案根據,我已經創造了這個:Socket編程的C,使用select()函數

//Server 

    sock_init(); //from SFL, see http://legacy.imatix.com/html/sfl/ 

    timeout = 50000; 

    serv_sock_input[0] = TCP(1234); 
    serv_sock_input[1] = UDP(9876); 

    input_protocols[0] = "tcp"; 
    input_protocols[1] = "udp"; 

    while (1) 
    { 
     FD_ZERO(&sock_set); 
     for (x = 0; x<number_of_inputs; x++) 
     { 
      FD_SET(serv_sock_input[x], &sock_set); 
     } 

     select_timeout.tv_sec = timeout; 
     select_timeout.tv_usec = 0; 

     if (select(0, &sock_set, NULL, NULL, &select_timeout) == 0) 
      printf("No requests"); 
     else 
     { 
      for (x = 0; x<number_of_inputs; x++) 
      { 
       if (FD_ISSET(serv_sock_input[x],&sock_set)) 
       { 
        printf("\nRequest on port %d: \n", x); 
        if ((strcmp(input_protocols[x],"tcp")) == 0) //in this case, 0 returned == TRUE 
        { 
         accept_socket(serv_sock_input[x]); 
         printf("Input TCP Port %d\n",x); 
         close_socket(serv_sock_input[x]); 
        } 
        else 
        { 
         printf("Input UDP Port %d\n",x); 
        } 
       } 
      } 
     } 
    } 
    sock_term(); 
} 

int TCP (unsigned short port) 
{ 
    int sock;       
    struct sockaddr_in servAddr; 

    if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) 
     exit(1); 

    memset(&servAddr, 0, sizeof(servAddr)); 
    servAddr.sin_family = AF_INET;   
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY); 
    servAddr.sin_port = htons(port);    

    if (bind(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0) 
     exit(1); 

    if (listen(sock, 5) < 0) 
     exit(1); 

    return sock; 
} 

int UDP (unsigned short port) 
{ 
    int sock;      /* socket to create */ 
    struct sockaddr_in servAddr; /* Local address */ 

    /* Create socket for sending/receiving datagrams */ 
    if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) 
     exit(1); 

    /* Construct local address structure */ 
    memset(&servAddr, 0, sizeof(servAddr)); /* Zero out structure */ 
    servAddr.sin_family = AF_INET;    /* Internet address family */ 
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */ 
    servAddr.sin_port = htons(port);  /* Local port */ 

    /* Bind to the local address */ 
    if (bind(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0) 
     exit(1); 


    return sock; 
} 

//Client 
sock_init(); 

    if ((client_sock_output = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) 
     exit(1); 

    memset(&client_addr, 0, sizeof(client_addr)); 
    client_addr.sin_family  = AF_INET; 
    client_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    client_addr.sin_port  = htons(1234); 

    if (connect(client_sock_output, (struct sockaddr *) &client_addr, sizeof(client_addr)) < 0) 
     exit(1); 

    closesocket(client_sock_output); 

    sock_term(); 

Wh在服務器啓動時,服務器在if(select(...))聲明處被阻止。

所以當我運行服務器,然後運行客戶端時,客戶端連接到服務器(有時在連接之前運行客戶端需要幾次)。然後if(select...))陳述不再是真實的,它進行到else。

之後,客戶端關閉連接和程序。但是,這是我的問題發生的地方,if(select(...))聲明總是錯誤的。我得到這個輸出:

Request on port 0: 
Input TCP Port 0 

Request on port 1: 
Input UDP Port 1 

這個輸出永遠重複。它怎麼不卡在if(select(...))

回答

5

您有兩個問題:您不明白accept()如何在TCP中工作,並且您需要讀取UDP中的傳入數據。

select()告訴你一個監聽套接字有連接來接受,或者讀取套接字有數據要讀。

要選擇停止告訴你這一點,你需要實際讀取數據或接受連接。

在你的UDP分支中,你需要調用receiv來實際獲取數據。如果你不這樣做,選擇將不斷告訴你,你有數據。

在你的TCP分支中,你調用accept_socket。我不知道你的實現是什麼,但關閉剛纔調用accept()的套接字很可能是錯誤的。 accept()爲你返回一個新的套接字 - 你應該用於IO的套接字。如果需要關閉任何東西,那就是新的套接字。

1

請檢查您爲什麼在服務器中安裝此軟件。

如果(選擇(0, & sock_set,NULL,NULL,& select_timeout)== 0)

如果(選擇(maxDescPlus1 & sock_set替換它, NULL,NULL,& select_timeout)== 0)

其中maxDescPlus1 - >是sel的描述符的數量ect加1值。