RTnet 개요

RTnet은 Xenomai의 실시간 네트워킹을 담당하는 구성 요소로, 주로 이더넷 망에서 실시간 데이터를 교환하는 데 사용된다. RTnet은 높은 우선순위 트래픽을 보장하며, 이는 네트워크 프로토콜 스택과 하드웨어 인터페이스에서 실시간 특성을 유지하도록 설계되었다.

설치

RTnet을 사용하기 위해서는 먼저 RTnet 패키지를 설치해야 한다. Xenomai와 RTnet의 설치는 아래와 같은 절차를 따른다.

패키지 설치

RTnet은 Xenomai와 함께 설치될 수 있다. 보통 소스 코드로 배포되며, 다음과 같은 명령어를 사용하여 설치할 수 있다.

$ sudo apt-get install xenomai
$ sudo apt-get install rtnet

RTnet 설정

RTnet을 설정하기 위해서는 여러 단계가 포함된다. 기본적으로 네트워크 인터페이스를 설정하고, 관련 모듈을 로드해야 한다.

네트워크 설정

RTnet 인터페이스를 설정하기 위해서는 Xenomai가 지원하는 네트워크 카드가 필요하다. RTnet에서 사용하는 실시간 네트워크 인터페이스는 rteth로 불리며, 이를 설정하기 위해서는 다음과 같은 절차를 따른다.

RTnet 모듈 로드

먼저 RTnet의 커널 모듈을 로드해야 한다. 이는 insmod 명령어를 사용하여 다음과 같이 로드할 수 있다. 예를 들어, rt_8139too 모듈을 사용하는 경우,

$ sudo insmod /path/to/rtnet/rt_8139too.ko

네트워크 인터페이스 설정

네트워크 인터페이스를 설정하려면, 먼저 인터페이스가 정상적으로 인식되었는지 확인해야 한다. 다음 명령어를 사용하여 네트워크 인터페이스 상태를 확인할 수 있다.

$ ifconfig -a

다음으로, rtifconfig 명령어를 사용하여 인터페이스를 설정할 수 있다.

$ sudo rtifconfig rteth0 up 192.168.1.1

이 명령어는 rteth0 인터페이스를 활성화하고, IP 주소를 192.168.1.1로 설정한다.

RTnet 드라이버 설정

RTnet은 여러 드라이버를 제공한다. 사용 중인 네트워크 카드에 맞는 드라이버를 선택하여 설정한다. 예를 들어, Realtek 8139 드라이버를 사용하려면 다음과 같다.

$ sudo modprobe rt_8139too

RTnet 인터페이스가 정상적으로 설정되었다면, rtifconfig 명령어를 사용하여 인터페이스를 확인할 수 있다.

$ rtifconfig

이제 RTnet을 사용하여 데이터를 송수신하는 단계에 대해 설명하겠다.

RTnet 애플리케이션 개발

RTnet 소켓 프로그래밍

RTnet을 이용한 소켓 프로그래밍은 일반적인 POSIX 소켓 프로그래밍과 유사하다. 다만, RTnet은 실시간 특성을 갖춰야 하므로 일부 옵션과 프레임워크가 추가된다.

다음은 RTnet을 사용하여 간단한 TCP 서버와 클라이언트를 구현하는 예제다.

TCP 서버

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <rtnet.h>

int main(){
    int server_fd, new_socket;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);

    // 소켓 생성
    if ((server_fd = rt_socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        return 1;
    }

    // 소켓 옵션 설정
    if (rt_setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
        perror("setsockopt");
        return 1;
    }

    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(8080);

    // 바인드작업
    if (rt_bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) {
        perror("bind failed");
        return 1;
    }

    // 리슨 대기
    if (rt_listen(server_fd, 3) < 0) {
        perror("listen");
        return 1;
    }

    // 클라이언트 연결 수락
    if ((new_socket = rt_accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) {
        perror("accept");
        return 1;
    }

    char buffer[1024] = {0};
    rt_recv(new_socket, buffer, 1024, 0);
    printf("Message from client: %s\n", buffer);

    rt_close(new_socket);
    rt_close(server_fd);
    return 0;
}

TCP 클라이언트

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <rtnet.h>

int main(){
    int sock = 0;
    struct sockaddr_in serv_addr;
    char *hello = "Hello from RTnet client";

    // 소켓 생성
    if ((sock = rt_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        printf("\n Socket creation error \n");
        return -1;
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(8080);

    // 서버 주소 입력
    if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0) {
        printf("\nInvalid address/ Address not supported \n");
        return -1;
    }

    // 서버와의 연결
    if (rt_connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        printf("\nConnection Failed \n");
        return -1;
    }

    rt_send(sock, hello, strlen(hello), 0);
    printf("Hello message sent\n");

    rt_close(sock);
    return 0;
}

실행 방법

  1. 먼저 서버 애플리케이션을 컴파일하고 실행한다. bash $ gcc server.c -o rt_server -lrtnet $ sudo ./rt_server
  2. 다른 터미널에서 클라이언트를 컴파일하고 실행한다. bash $ gcc client.c -o rt_client -lrtnet $ sudo ./rt_client

주의사항

RTnet을 사용할 때는 네트워크 하드웨어와 실시간 특성이 요구되는 정확한 설정이 필요하다. 사용 중에는 실시간 네트워크 트래픽이 끊기지 않도록 주의해야 한다.