2017-12-03 8 views
0

한 번에 하나의 클라이언트가 연결하고 명령을 실행 한 다음 닫을 수있는 서버가 있습니다. 서버는 "현재 연결된"IP 주소의 배열 목록을 유지하여 누가 명령을 수락 할지를 안다. 문제는 같은 클라이언트 인 것처럼 처리되는 유사한 IP 주소에서 실행되는 두 개의 클라이언트가 있다는 것입니다.서버는 서로 다른 IP를 가진 두 개의 클라이언트가 같다고 생각합니다. 1 클라이언트 (C 소켓 프로그래밍)

예 : 클라이언트 A의 IP 주소는 255.255.255.153입니다. 나는 연결하도록 말하면 모든 것이 잘 작동합니다. 클라이언트 B의 IP 주소는 255.255.255.156입니다. 연결하라는 말을하고 서버가 이미 연결되어 있다고 말합니다.

내 strcmp가 올바르지 않습니까? 다른 것입니까? 도와주세요. inet_ntoa()에 대한

// Variable Declarations 

int SIZE = 10; // Max number of agents 
char *agents[SIZE], // List of current connections 
    *times[SIZE]; // List of connection times 
char buffer[MAXBUF]; 
int bytes_read = 0; 
int total_bytes_read = 0; 
int found = 0, // Bool flag 
    i; 
struct tm ts; 
struct timeval connected[SIZE], 
       current, 
       difference; 
     time_t TIME; 

// Initialize array to NULL 
for(i = 0; i < SIZE; i++) { 
    agents[i] = NULL; 
} 

// Infinite Loop 
while (true) { 
    struct sockaddr_in client; 
    int clientSocket; 
    socklen_t clientLength = sizeof(client); 
    memset(&client, 0, clientLength); 
    clientSocket = accept(sd, (struct sockaddr *)&client, &clientLength); 

    memset(buffer,0,MAXBUF); 
    bytes_read = read(clientSocket, buffer, MAXBUF); 
    if (bytes_read < 0) 
     break; 
    fprintf(stdout,"\nRead %d bytes: [%s]\r\n", bytes_read,buffer); 

    char *connectedIP = inet_ntoa(client.sin_addr); 

    // Option 1: 
    if ((strcmp(buffer, "#JOIN")) == 0) { // Join list of connected agents 
     found = 0; 

     // Get current time for log 
     TIME = time(NULL); 
     ts = *localtime(&TIME); 

     // Print message to log 
     char buf[80]; 
     strftime(buf, sizeof(buf), "%a %Y-%m-%d %H:%M:%S %Z", &ts); 
     fprintf(log, "%s: Received a \"#JOIN\" action from agent \"%s\"", buf, connectedIP); 
     fprintf(log, "\n\n"); 
     fflush(log); 

     printf("\n%s Joining", connectedIP); 
     fflush(stdout); 
     // Handle #JOIN request appropriately 
     for (i = 0; i < SIZE; i++) { 
      printf("\nAgent[%d] == %s", i, agents[i]); 

      if (agents[i] == NULL) { 

      } 
      else if (strcmp(agents[i], connectedIP) == 0){ // Agent found in list 
       found = 1; 

       printf("\n%s is equal to %s", agents[i], connectedIP); 
       fflush(stdout); 

       // Write to agent 
       char response[] = "#ALREADY MEMBER"; 
       write (clientSocket, response, strlen(response)); 

       // Get time for log 
       TIME = time(NULL); 
       ts = *localtime(&TIME); 

       // Write to log 
       char buf[80]; 
       strftime(buf, sizeof(buf), "%a %Y-%m-%d %H:%M:%S %Z", &ts); 
       fprintf(log, "%s: Responded to agent \"%s\" with \"#ALREADY MEMBER\"", buf, connectedIP); 
       fprintf(log, "\n\n"); 
       fflush(log); 
       i = SIZE; 
      } 
     } 
     if (found == 0) { // Save IP to list/queue 
      for(i = 0; i < SIZE; i++) { 
       if (agents[i] == NULL) { 

        // Save IP to array 
        agents[i] = connectedIP; 

        printf("\nagents[%d] = %s\n", i, connectedIP); 
        fflush(stdout); 

        // Save time to arrays 
        gettimeofday(&connected[i], NULL); 
        TIME = time(NULL); 
        times[i] = TIME; 
        ts = *localtime(&TIME); 

        // Write to log 
        char buf[80]; 
        strftime(buf, sizeof(buf), "%a %Y-%m-%d %H:%M:%S %Z", &ts); 
        fprintf(log, "%s: Responded to agent \"%s\" with \"#OK\"", buf, connectedIP); 
        fprintf(log, "\n\n"); 
        fflush(log); 

        // Write to agent 
        char response[] = "#OK"; 
        write (clientSocket, response, strlen(response)); 
        i = SIZE; 
       } 
      } 
     } 
     memset(&client, 0, clientLength); 
    } 
+1

'agents' 배열이 정의 된 방식, AFAICS를 표시하지 않습니다. 적절하게 정의하고 IPv4 주소를 문자열로 저장한다면,'strcmp()'는 괜찮을 것입니다. 그러나 각 주소를 저장하려면 16 바이트를 허용해야합니다. '192. 3 단위' '192 \ 0'중 하나입니다. 따라서 표시되지 않은 코드가 많은 경첩입니다. MCVE ([MCVE])를 만드는 방법에 대해 읽어보십시오. 당신이 보여주는 것은 MCVE가 아닙니다. –

+0

'agents'선언을 추가했으며 댓글에 대해 유감스럽게 생각합니다. 고쳤다. – Carr

+0

당신은'agents [i] = connectedIP; '를 저장한다. 선언되지 않은 변수이지만, 모든 에이전트에 대해 같은 공간을 사용하고있는 가능성이있다. 그래서 당신이 연결된 에이전트를 반복하여 이름을 출력한다면, 그들이 모두 똑같은 것을 알았습니다. 나는'strdup (connected IP)'와 같은 것을 기대할 것이다. 그러나 그것은 여전히 ​​MCVE가 아니므로 사람들이 당신을 도우려는 것이 편리하지 않습니다. –

답변

1

POSIX 및 사양은 정보가 포함

inet_ntoa() 기능은 인터넷 표준 점 표기법의 문자열에 의해 지정된 인터넷 호스트 주소로 변환된다.

inet_ntoa() 함수는 스레드로부터 안전 할 필요는 없습니다. 네트워크 바이트 순서로 주어진

inet_ntoa() 기능의 인터넷 호스트 주소를 변환 :

inet_ntoa()의 리눅스 매뉴얼 페이지가 동작하고 POSIX 경고가 해당 플랫폼에 무엇을 의미하는지 방법에 대한 자세한 명시 적입니다

, IPv4 점으로 구분 된 십진수 표기법의 문자열로 변환합니다. 문자열은 정적으로 할당 된 버퍼에 반환되며 이후의 호출은이를 덮어 씁니다.

나는 (예, 그 주석의 첫 번째 부분은 정확하지 않았다 - 그것은 아이폰 응용 프로그램에 하드 읽는 코드입니다)를 comment에서 언급 한 바와 같이 :

...하지만 당신이 사용하고 있는지 가능성이 있습니다 모든 에이전트에 대해 동일한 공간을 사용하므로 연결된 에이전트를 반복하여 이름을 인쇄하면 모두 동일하다는 것을 알 수 있습니다. 나는 거기에서 strdup(connectedIP)와 같을 것을 기대할 것이다.

이 코드는 단순히 agents 배열에 inet_ntoa()에 의해 반환 된 포인터를 저장하기 때문에, 배열은 항상 마지막 호스트가 고개를 포함하고 있다는 것을 의미한다. inet_ntoa()에서 결과의 사본을 가져 와서 저장하고 저장소를 관리해야합니다. 가장 간단한 방법은 strdup()으로 사본을 가져 오는 것입니다.하지만 연결이 끊어지면 해제해야합니다.

strdup() 또는 이와 동등한 메커니즘을 사용하면 즉각적인 문제를 해결해야합니다. 메모리 누출을 조심하십시오.

+0

나는 strdup (inet_ntoa (client.sin_addr))을 끝내고 완벽하게 작동합니다. 정말 고맙습니다. 나는'connectedIP'에 결과를 저장하는 것이 포인터가 아니라 실제 문자열을 저장할 것이라고 생각했습니다. 다시 한 번 감사드립니다. – Carr