네트워크

TCP/IP C언어 통신

code BlueJ 2025. 4. 10. 23:29
반응형

- 소켓 생성

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;

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

반응형