2013-12-23 60 views
0

這是一個C++服務器應用程序,它可以與所有基於UDP協議的客戶端進行通信。當用戶從客戶端登錄到服務器時,客戶端應用程序向服務器註冊一個UDP通道,並且該通道採用固定格式:IP +端口,這意味着如果IP保持不變,則無論用戶登錄到客戶端寄存器同一頻道。基於UDP的服務器無法區分不同的用戶

服務器的套接字層維護一個心跳機制,如果它在3分鐘內沒有收到來自該信道的任何心跳包,將刪除該信道。一切正常,直到客戶端關閉,例如網線被拔掉。看看下面的一幕:

1. User-A logs into server. The Client registers channel (IP:Port) 
     to the server. Because the UDP channel is alive, so the Server 
     sets the User status of User-A as Online. 

    2. Kill the client process, and within 3 minutes(before the channel 
     timeouts in server), let User-B logs into server from the same 
     computer. Because the IP remains unchanged, so actually the client 
     registers a same (IP:PORT) pair to the server as it did when User-A 
     logs in. 

    3. Since the Server receives packets from (IP:PORT), so it considers 
     User-A is still alive, thus setting the user status of User-A as 
     Online which is not right anymore. 

在上述情況下,服務器無法區分不同的用戶從同一臺計算機上,這會導致錯誤的用戶狀態記錄下來。有人知道如何解決這個問題嗎?

+0

您可以實施某種認證。 – smeso

+1

將通道簽名從「(IP:PORT)」擴展到「(IP:PORT:USER)」 –

回答

0

我沒有理由認爲除非客戶端應用程序明確綁定了UDP套接字,否則任何兩個用戶的源端口號都是相同的。啓動通信的客戶通常可以像使用短暫端口一樣有效。對於您的特定用例,臨時端口可能會或可能不會足夠隨機,下面的代碼顯示瞭如何從入站UDP數據訪問客戶端端口。如果它們不夠隨機,則可以將會話cookie或用戶cookie編碼到協議中。

#include <sys/socket.h> 
#include <sys/types.h> 
#include <arpa/inet.h> 
#include <stdio.h> 
#include <string.h> 

int 
main() { 
     /*- setup UDP socket on 8500 */ 
     int rc; 
     int server_socket; 
     struct sockaddr_in server_address; 

     server_socket = socket(AF_INET, SOCK_DGRAM, 0); 
     if (server_socket < 0) { 
       perror("failed to init socket"); 
       return 1; 
     } 

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

     rc = bind(server_socket, (struct sockaddr*) &server_address 
       , sizeof(server_address)); 

     if (rc < 0) { 
       perror("failed to bind"); 
       return 2; 
     } 

     /* - receive from UDP socket and print out origin port - */ 
     char buffer[4096]; 
     struct sockaddr_in client_address; 
     int client_address_len = sizeof(client_address); 

     rc = recvfrom(server_socket 
        , buffer 
        , sizeof(buffer) 
        , 0 
        , (struct sockaddr*) &client_address 
        , &client_address_len); 

     if (rc < 0) 
       return 3; 

     fprintf(stderr, "%s %d\n", buffer, ntohs(client_address.sin_port)); 

     return 0; 
} 
相關問題