TCP/IP C언어 통신

    반응형

    - 소켓 생성

    server_socket = socket(PF_INET, SOCK_STREAM, 0);

    옵션이 0이면 블로킹모드이다. 블로킹모드는 recv()함수에서 리턴하지 않고 기다린다.

     

    -아래와 같이 timeout을 주면 일정 시간 후에 타임아웃 에러낸다.

    setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));

     

    -아래와 같이 select함수에서 timeout 에러를 낼 수도 있다.

    보통 select에 타임아웃을 많이 준다.

     

    tv.tv_sec = 10;      // 10초 timeout
    tv.tv_usec = 0;
    int ret = select(sock + 1, &read_fds, NULL, NULL, &tv);

     

    참고로

     int ret = select(sockfd + 1, &readfds, &writefds, NULL, &timeout);

    일시 writefds는 항상 true이기 때문에 return되고 timeout은 무시됨.

    select함수의 timeout은 주기를 뜻하는거지 에러를 뜻하는게 아님.

    타임아웃을 보통 0.1~1초로 줘서 빨리 루프를 돌게 만듬.

    보통 writefds는 설정하지않고 has_to_send 같은 변수를 추가로 설정해서 같이씀.

    안그러면 send()로직을 계속 실행 할것이기 때문

     

    TCS, UCS 코드

    // tcp_polling_sender.c
    
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <fcntl.h>
    #include <sys/time.h>
    #include <netinet/in.h>
    
    #define POLLING_INTERVAL 1800  // 3분 = 1800 x 0.1초
    #define BUF_SIZE 1024
    
    // 전역 변수
    int has_data_to_send = 0;
    char send_buf[BUF_SIZE] = {0};
    
    // --- TCS에서 tpcall() 호출될 때 실행됨 ---
    int svc_main(int svc, char *in_buf, int in_len, char *out_buf, int *out_len) {
        printf("[TCS 수신] 전문 수신: %s\n", in_buf);
    
        strncpy(send_buf, in_buf, sizeof(send_buf) - 1);
        send_buf[sizeof(send_buf) - 1] = '\0';
        has_data_to_send = 1;
    
        strcpy(out_buf, "OK");
        *out_len = strlen(out_buf);
        return 0;
    }
    
    // --- 메인 루프: select로 송수신 처리 ---
    int usermain(int argc, char **argv) {
        int sockfd = socket(AF_INET, SOCK_STREAM, 0);
        struct sockaddr_in server_addr;
    
        // 소켓 연결 설정
        server_addr.sin_family = AF_INET;
        server_addr.sin_port = htons(12345);  // 포트 설정
        server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    
        connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    
        int tick = 0;
    
        while (1) {
            fd_set readfds, writefds;
            struct timeval timeout;
    
            FD_ZERO(&readfds);
            FD_ZERO(&writefds);
            FD_SET(sockfd, &readfds);
            if (has_data_to_send) {
                FD_SET(sockfd, &writefds);
            }
    
            timeout.tv_sec = 0;
            timeout.tv_usec = 100000;  // 0.1초
    
            int ret = select(sockfd + 1, &readfds, &writefds, NULL, &timeout);
    
            if (ret > 0) {
                // 수신 처리
                if (FD_ISSET(sockfd, &readfds)) {
                    char recv_buf[BUF_SIZE] = {0};
                    int len = recv(sockfd, recv_buf, sizeof(recv_buf), 0);
                    if (len > 0) {
                        printf("[TCP 수신] %s\n", recv_buf);
                    }
                }
    
                // 송신 처리
                if (has_data_to_send && FD_ISSET(sockfd, &writefds)) {
                    int sent = send(sockfd, send_buf, strlen(send_buf), 0);
                    if (sent > 0) {
                        printf("[TCP 송신] %s\n", send_buf);
                        has_data_to_send = 0;
                    }
                }
            }
    
            // --- 3분마다 polling 전문 전송 ---
            tick++;
            if (tick >= POLLING_INTERVAL) {
                tick = 0;
    
                // 예시: "1001 POLLING"
                snprintf(send_buf, sizeof(send_buf), "1001 POLLING\n");
                has_data_to_send = 1;
    
                printf("[POLLING 발생] 전문 생성 완료\n");
            }
        }
    
        close(sockfd);
        return 0;
    }

     

    timeout을 0.1초로 줬기에 rick은 0.1초에 1씩 쌓인다. 그래서 1800이 되면 3분 타임아웃이난다.

     

    extern int has_data_to_send;

    선언이 아니라 이 변수 어딘가엔 있겠지란 선언. 순서 상관 없다.

    반응형

    댓글