티스토리 뷰

초기 동기화 데이터는 동기화 리스트를 사용해 만든 해쉬 테이블의 데이터를 전송한다.

이때 직렬화하는 과정을 거쳐서 전송을 용이하게 만들지만, 이건 다음에 설명한다.

 

이번에는  어떻게 동기화 리스트와 파일들의 변경을 감지하고, 어떻게 처리하는 지를 살펴보겠다.

해쉬 테이블 관련 내용이 많으니 이전 게시글을 먼저보는 것을 추천한다.

2024.02.14 - [프로젝트] - 프로젝트: 파일 동기화 - 해쉬 테이블

 

프로젝트: 파일 동기화 - 해쉬 테이블

보통 c언어에서는 데이터 셋을 구조체를 통해 구현한다. 다른 언어가 객체와 같이 key-value 쌍으로 유연하게 속성을 추가하고, 관리할 수 있다. 그러나 c는 구조페를 선언할때 사용할 맴버를 미리

lhs9602.tistory.com

 

 

 

기본 구조


while (TRUE)
    {        
        select(max_sd + 1, &readfds, NULL, NULL, &timeout);
        // 새로운 연결 요청 확인
        if (FD_ISSET(server_socket_fd, &readfds))
        {
        	...
            continue;
        }

        client_close = 0;
        for (int index = 0; index < MAX_CLIENTS; index++)
        {
            if (0 == client_socket[index])
            {
                continue;
            }
            if (FD_ISSET(client_socket[index], &readfds))
            {
                client_close = 1;
                client_socket[index] = client_connect_check(client_socket[index]);
            }
        }

        if (1 == client_close)
        {
            continue;
        }
        // 기존의 상태를 -1로 변경
        change_state(file_list, -1);

        // 변경 사항 확인
        if (1 == update_check_sync_file(&file_list, sync_file_path))
        {
            transfer_header_t update_header;
            memset(&update_header, 0, sizeof(transfer_header_t));
            update_header_set(file_list, &update_header, 3);

            if (0 != update_header.total_size)
            {
                printf("변경 데이터 전송\n");
                update_data_serialized(file_list, update_header, &update_data);  
                thread_create(&update_data, &update_header, client_socket);

                if (NULL != update_data)
                {
                    free(update_data);
                    update_data = NULL;
                }
            }

            // 기존 초기 데이터 할당 해제
            if (NULL != serialized_data)
            {
                free(serialized_data);
                serialized_data = NULL;
            }

            // 초기 전송 데이터에 변경사항을 반영하여 다시 생성
            transfer_header.data_type = 3;
            transfer_header.total_size = total_file_size_cal(file_list);
            transfer_header.file_count = HASH_COUNT(file_list);

            file_serialized(&serialized_data, file_list, transfer_header);

        }
        // 상태를 0으로 초기화
        change_state(file_list, 0);
       }

 

위는 server의 select 코드이다.

select()는 대기하다가 지정한  파일 디스크립터에서 이벤트가 발생시 다음 코드를 실행시킨다.

이번에는 timeout이라는 timeval 구조체를 사용하여 일정시간마다 주기적으로 다음 코드를 실행하도록 만들었다.

 

select 이후의 코드는 3가지 분류할 수 있다.

  1. if (FD_ISSET(server_socket_fd, &readfds)): 새로운 통신 요청을 확인하고, 연결하는 파트. server_socket_fd 소켓에 요청이 들어올 때만 동작하며, 연결 이후 continue을 통해 다른 코드가 실행되는 것을 방지한다.

  2. if  (FD_ISSET(client_socket[index], &readfds): 기존에 연결된 클라이언트에서 요청이 들어올때 작동하는 파트. 클라이언트에서 서버로 데이터를 전송하는 경우는 없기에, 클라이언트가 종료되면서 보내는 신호를 감지하는 역할이다. 그 후, 연결이 종료된 소켓을 정리하는 역할을 한다. 이것도 실행되면 client_close를 통해 continue을 실행하여 다른 파트와 겹치지 않도록한다.
  3. if (1 == update_check_sync_file(&file_list, sync_file_path)): 변경 사항을 감지하는 파트이다. 이 파트는 오직 timeout에 설정된 시간이 경과될때만 실행된다. update_check_sync_file함수로 동기화 리스트와 파일 리스트를 비교해 추가 혹은 제거,변경된 파일을 찾고, 이를 처리하는 파트이다. 

이번 게시글은 3번의 변경사항 파트에 대해서 자세히 설명할 것이다.

 

변경사항 감지


int update_check_sync_file(file_list_t **file_list, char *sync_file_path)
{

    FILE *file = fopen(sync_file_path, "r");
    static char buffer[MAX_LENGTH];
    memset(buffer, 0, sizeof(buffer));

    int result = 0;
    char *token = NULL;
    while (fgets(buffer, sizeof(buffer), file) != NULL)
    {

        if (2 == relative_path_check(buffer))
        {
            token = absolute_path_change(buffer);
        }
        else
        {
            token = strtok(buffer, " \n");
        }

        if (1 == file_path_check(token))
        {
            file_list_t *current_file_data = NULL;
            current_file_data = find_file_data(*file_list, token);
            if (NULL == current_file_data)
            {
                result = 1;
                add_path(file_list, token);
            }
            else if (1 == check_path(current_file_data, token))
            {
                result = 1;
            }
        }
    }
    fclose(file);

    delete_state_clear(file_list);
    print_all_files(file_list);

    return result;
}

위 함수에서 이전 열었던 동기화 리스트를 다시 읽고, 파일의 경로를 추출한다.

그리고 그 경로가 파일 리스트에 있는지 확인하고 없다면, 추가한다.

 

만약 있다면, 해당 요소에 저장된 업데이트 시간과 stat으로 탐색한 업데이트 시간과 비교하여 다르다면 변경된 파일로 간주한다. 이렇게 변경사항이 있다면 변경 데이터를 반영하고 state 맴버에 1을, 변경사항이 없다면 0을 넣는다. 

 

또한 해당 함수 실행 전에, 모든 파일 리스트의 state를 -1로 변경하고 동기화 리스트에서 해당 경로가 없다면 계속 -1을 유지한다.

모든 경로를 추출해도 -1인 state는 제거 대상이기에 state가 -1인 요소는 모두 제거한다.

 

그리고 이렇게 변경, 추가가 발생하면 1을 리턴하여 if (1 == update_check_sync_file(&file_list, sync_file_path))의 조건문을 만족하고 다음 로직을 진행한다.

 

만약 추가나 변경이 없다면 0을 반환하고 다시 대기 상태로 돌아간다.

 

그리고 state가 1인 요소를 클라이언트에 전송후, 모든 파일리스트의 state를 0으로 초기화한다. 

 

 

이 다음은 변경사항 데이터 전송과 스레드에서 설명하겠다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함