1. 

포트 21111은 로컬 호스트(127.0.0.1)에서만 수신 대기 상태입니다. 
이는 이 포트가 현재 시스템 내의 로컬 네트워크 인터페이스에서만 접근 가능하다는 것을 의미합니다. 
외부 네트워크에서 이 포트에 접근할 수 없습니다.
root@sinfo:~# netstat -an | grep 21111
tcp        0      0 127.0.0.1:21111         0.0.0.0:*               LISTEN


2. 

포트 21111은 모든 네트워크 인터페이스(0.0.0.0)와 로컬 IPv6 주소(::1)에서 수신 대기 상태입니다. 
이는 포트 21111 가 외부 네트워크와 로컬 네트워크 모두에서 접근 가능하다는 것을 의미합니다. 
root@sinfo:~# netstat -an | grep 21111
tcp        1      0 0.0.0.0:21111           0.0.0.0:*               LISTEN
tcp6       0      0 :::21111                :::*                    LISTEN
root@sinfo:~#

1번과 2번의 소스차이는(?)

#if(false)
        private void Init()
        {
            //소켓 객체 생성 (TCP 소켓)
            listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            //엔드포인트에 소켓 바인드(Bind)
            IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 21111);
            listener.Bind(localEndPoint);

            //Listen소켓의 대기열의 길이를 설정합니다.
            listener.Listen(10);

            PublicApiNM.SendToDebug(3, "()(Init)(Listen)");

            while (true)
            {
                try
                {
                    Socket handler = listener.Accept();

                    PublicApiNM.SendToDebug(3, "()(Init)(Accept)");

                    //richTextBox1.Text = richTextBox1.Text + "Socket handler = listener.Accept() OK" + "\n";

                    Thread RealSocModel = new Thread(new ParameterizedThreadStart(SocketRunHandler));
                    RealSocModel.Start(handler);
                }
                catch (Exception ex)
                {
                    //
                }
            }
            listener.Close();
        }
#endif
#if(true)
private void Init()
{
    // IPv4와 IPv6 소켓 객체 생성 (TCP 소켓)
    ipv4Listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    ipv6Listener = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);

    // IPv4와 IPv6 엔드포인트 설정
    IPEndPoint ipv4EndPoint = new IPEndPoint(IPAddress.Any, 21111); // 모든 IPv4 주소에서 수신 대기
    IPEndPoint ipv6EndPoint = new IPEndPoint(IPAddress.IPv6Any, 21111); // 모든 IPv6 주소에서 수신 대기

    // 소켓을 엔드포인트에 바인드
    ipv4Listener.Bind(ipv4EndPoint);
    ipv6Listener.Bind(ipv6EndPoint);

    // 소켓의 대기열 길이 설정
    ipv4Listener.Listen(10);
    ipv6Listener.Listen(10);

    PublicApiNM.SendToDebug(3, "()(Init)(Listen)");

    while (!_shouldStop)
    {
try
{
    // 소켓이 닫혔는지 확인하고, 닫혔으면 루프 종료
    if (ipv4Listener.Poll(1000, SelectMode.SelectRead) && ipv4Listener.Available == 0)
    {
break;
    }

    if (ipv6Listener.Poll(1000, SelectMode.SelectRead) && ipv6Listener.Available == 0)
    {
break;
    }

    // 클라이언트 연결 수신 대기
    Socket ipv4Handler = ipv4Listener.Accept();
    Socket ipv6Handler = ipv6Listener.Accept();

    PublicApiNM.SendToDebug(3, "()(Init)(Accept)");

    // 새 스레드에서 클라이언트 처리
    Thread ipv4Thread = new Thread(new ParameterizedThreadStart(SocketRunHandler));
    ipv4Thread.Start(ipv4Handler);

    Thread ipv6Thread = new Thread(new ParameterizedThreadStart(SocketRunHandler));
    ipv6Thread.Start(ipv6Handler);
}
catch (SocketException ex)
{
    if (_shouldStop)
    {
// _shouldStop이 true일 경우, listener가 닫히면서 예외 발생할 수 있음
break;
    }

    // 그 외의 소켓 예외 처리
    PublicApiNM.SendToDebug(3, "()(Init)(Exception):" + ex.Message);
}
catch (Exception ex)
{
    // 기타 예외 처리
    PublicApiNM.SendToDebug(3, "()(Init)(Exception):" + ex.Message);
}
    }

    // 소켓 닫기
    ipv4Listener.Close();
    ipv6Listener.Close();
    PublicApiNM.SendToDebug(3, "()(Init)(Stopped)");
}

public void StopInitThread()
{
    _shouldStop = true;

    // 소켓을 닫아 블로킹 호출에서 예외를 발생시키도록 함
    if (ipv4Listener != null)
    {
ipv4Listener.Close();
    }
    if (ipv6Listener != null)
    {
ipv6Listener.Close();
    }
}
#endif

windows->ubuntu migration(c#)

1. ubuntu.krx.recv.SQLite.redis.json Conver.redis send(by clientQueueKey)
- absolute path
- except using Forms

2. hometrade.redis.BlPOP.display.console


dotnet new console -o redisconsole
cd redisconsole
source coding..........................................................................................
dotnet build
dotnet run
dotnet add package Newtonsoft.Json
dotnet add package ServiceStack
dotnet add package ServiceStack.Redis

WPF에 Json데이타 표시(정보분배 - No Loop,Loop Case)

case1) 정보분배 - No Loop Case.
case2) 정보분배 - Loop Case.

<Window x:Class="sampleNM.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="REDIS Real Time BLPOP" Height="800" Width="1200"
        KeyDown="Window_KeyDown"
        WindowStartupLocation="Manual"
        Left="10"
        Top="10">
    <Grid>
        <!-- Define Rows for layout -->
        <Grid.RowDefinitions>
            <RowDefinition Height="0.1*" />  <!-- 10% of available space -->
            <RowDefinition Height="0.4*" />  <!-- 50% of available space -->
            <RowDefinition Height="0.2*" />  <!-- 40% of available space -->
            <RowDefinition Height="0.3*" />  <!-- 40% of available space -->
        </Grid.RowDefinitions>

        <!-- Container for Time data -->
        <ScrollViewer Grid.Row="0" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" Margin="10">
            <Border BorderBrush="Black" BorderThickness="1" Margin="5">
                <StackPanel Orientation="Vertical">
                    <TextBlock Text="[Time Information]" FontWeight="Bold" FontSize="12" Margin="0,0,0,0"/>
                    <StackPanel x:Name="TimeStackPanel" Orientation="Vertical">
                        <!-- Time data will be loaded here -->
                    </StackPanel>
                </StackPanel>
            </Border>
        </ScrollViewer>

        <!-- Container for JSON data -->
        <ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" Margin="10">
            <Border BorderBrush="Black" BorderThickness="1" Margin="5">
                <StackPanel Orientation="Vertical">
                    <TextBlock Text="[REDIS JSON Information-NOT.LOOP.DATA]" FontWeight="Bold" FontSize="12" Margin="0,0,0,0"/>
                    <StackPanel x:Name="DataStackPanel" Orientation="Vertical">
                        <!-- JSON data will be loaded here -->
                    </StackPanel>
                </StackPanel>
            </Border>
        </ScrollViewer>

        <!-- Container for complex JSON data -->
        <ScrollViewer Grid.Row="2" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" Margin="10">
            <Border BorderBrush="Black" BorderThickness="1" Margin="5">
                <StackPanel Orientation="Vertical">
                    <TextBlock Text="[REDIS COMPLEX.JSON Information-SECURITIES.TRADE]" FontWeight="Bold" FontSize="12" Margin="0,0,0,0"/>
                    <DataGrid x:Name="DataGrid" AutoGenerateColumns="False" Margin="10">
                        <DataGrid.Columns>
                            <DataGridTextColumn Header="DataClass" Binding="{Binding DataClass}" />
                            <DataGridTextColumn Header="InfoMarketClass" Binding="{Binding InfoMarketClass}" />
                            <DataGridTextColumn Header="StockCode" Binding="{Binding StockCode}" />
                            <DataGridTextColumn Header="SerialNo" Binding="{Binding SerialNo}" />
                            <DataGridTextColumn Header="AskSecuritiesTradeNumber" Binding="{Binding AskSecuritiesTradeNumber}" />
                            <DataGridTextColumn Header="AskTradeVolume" Binding="{Binding AskTradeVolume}" />
                            <DataGridTextColumn Header="AskTradeAmount" Binding="{Binding AskTradeAmount}" />
                            <DataGridTextColumn Header="BidSecuritiesTradeNumber" Binding="{Binding BidSecuritiesTradeNumber}" />
                            <DataGridTextColumn Header="BidTradeVolume" Binding="{Binding BidTradeVolume}" />
                            <DataGridTextColumn Header="BidTradeAmount" Binding="{Binding BidTradeAmount}" />
                            <DataGridTextColumn Header="EndOfText" Binding="{Binding EndOfText}" />
                        </DataGrid.Columns>
                    </DataGrid>
                </StackPanel>
            </Border>
        </ScrollViewer>

        <!-- Container for complex JSON data -->
        <ScrollViewer Grid.Row="3" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" Margin="10">
            <Border BorderBrush="Black" BorderThickness="1" Margin="5">
                <StackPanel Orientation="Vertical">
                    <TextBlock Text="[REDIS COMPLEX.JSON Information-QUOTE.10]" FontWeight="Bold" FontSize="12" Margin="0,0,0,0"/>
                    <DataGrid x:Name="QuoteDataGrid" AutoGenerateColumns="False" Margin="10">
                        <DataGrid.Columns>
                            <DataGridTextColumn Header="DataClass" Binding="{Binding DataClass}" />
                            <DataGridTextColumn Header="InfoMarketClass" Binding="{Binding InfoMarketClass}" />
                            <DataGridTextColumn Header="DistributeStockIndex" Binding="{Binding DistributeStockIndex}" />
                            <DataGridTextColumn Header="BoardID" Binding="{Binding BoardID}" />
                            <DataGridTextColumn Header="SessionID" Binding="{Binding SessionID}" />
                            <DataGridTextColumn Header="StockCode" Binding="{Binding StockCode}" />
                            <DataGridTextColumn Header="StockSeq" Binding="{Binding StockSeq}" />
                            <DataGridTextColumn Header="TradingProcessingTime" Binding="{Binding TradingProcessingTime}" />
                            <DataGridTextColumn Header="AskQuote" Binding="{Binding AskQuote}" />
                            <DataGridTextColumn Header="BidQuote" Binding="{Binding BidQuote}" />
                            <DataGridTextColumn Header="AskQuoteVolume" Binding="{Binding AskQuoteVolume}" />
                            <DataGridTextColumn Header="BidQuoteVolume" Binding="{Binding BidQuoteVolume}" />
                            <DataGridTextColumn Header="TotalAskQuoteRemainder" Binding="{Binding TotalAskQuoteRemainder}" />
                            <DataGridTextColumn Header="TotalBidQuoteRemainder" Binding="{Binding TotalBidQuoteRemainder}" />
                            <DataGridTextColumn Header="EstimatedTradePrice" Binding="{Binding EstimatedTradePrice}" />
                            <DataGridTextColumn Header="EstimatedTradeVolume" Binding="{Binding EstimatedTradeVolume}" />
                            <DataGridTextColumn Header="EndText" Binding="{Binding EndText}" />
                        </DataGrid.Columns>
                    </DataGrid>
                </StackPanel>
            </Border>
        </ScrollViewer>
    </Grid>
</Window>

Linux sinfo 5.4.0-165-generic #182-Ubuntu 에서 정보분배/REDIS/SQLite/실행하기/BUILD/RUN/
Linux sinfo 5.4.0-165-generic #182-Ubuntu 에서 정보분배/REDIS/SQLite/실행하기/ BUILD/RUN/

root@sinfo:~# uname -a
Linux sinfo 5.4.0-165-generic #182-Ubuntu SMP Mon Oct 2 19:43:28 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
root@sinfo:~#

 

콘솔프로그램을 작성시에 쓰레드를 발생시키고 종료를 막기위해서 반복문을 사용하는것 외에는
방법이 없는것 같았지만, 아래와 같은 방법을 쓰면 될듯함/

 

using System;
using System.Threading;

class Program
{
    // ManualResetEvent 객체 생성
    private static ManualResetEvent manualResetEvent = new ManualResetEvent(false);

    static void Main()
    {
        Console.WriteLine("Main 스레드 시작");

        // 새로운 스레드 시작
        Thread thread = new Thread(WorkerThread);
        thread.Start();

        // ManualResetEvent를 통해 메인 스레드를 대기시킴
        manualResetEvent.WaitOne();

        Console.WriteLine("Main 스레드 종료");
    }

    static void WorkerThread()
    {
        Console.WriteLine("Worker 스레드 시작");

        // 일부 작업을 수행
        Thread.Sleep(3000); // 예: 3초 동안 작업을 수행한다고 가정

        Console.WriteLine("Worker 스레드 종료");

        // 작업이 완료되면 ManualResetEvent를 설정하여 Main 스레드를 깨움
        manualResetEvent.Set();
    }
}

정보분배수신/SQLite저장/REDIS전송/REDIS BLPOP/WPF/

1. KRX정보분배 TCP 데이타 수신
2. SQLite DataBase 저장
3. JSON포맷으로 변환
4. REDIS전송
5. REDIS BLPOP Designed by WPF(기존 Prompt) - 해당부분 아래 이미지로 제공

5.1 <string,stgring> JSON 타입
5.2 <string,List>  JSON 타입으로 나누어서 표시해야 합니다.

1. KRX

2. MDIRedisTicker Server
2.1 - Tcp Recv & Parse
2.2 - SQLite Database
2.3 - Push TO Redis Server

3. HomeTradeCli.exe
3.1 - Pop From Redis Server


KRX)
[2024-08-01 19:18:53.316][00099][00079][IA000K2S09PKRD020020354090034000970.33+000000.55000000000202000000035314    ]
HTS)
[Title+Time]:ExturePlusTotalKseIndex[2024-08-01 19:18:53.326]
[Redis++Key];1127001637919216845106
[POP---Data];{"data_tp_val":"IA","info_tp_val":"000","if_idx_id":"K2S09P","std_cd":"KRD020020354","idx_calc_tm":"090034","if_calc_idx":"000970.33","cmpprevdd_idx_sgn":"+","cmpprevdd_calc_idx":"000000.55","idx_acc_trdvol":"000000000202","idx_acc_trdval":"000000035314","filr_val4":"    ","ms_msg_end_keywrd":"NULL"}

KRX -> HTS까지 걸린시간은( [2024-08-01 19:18:53.316] - [2024-08-01 19:18:53.326] ) 의 시간 차이를 보이고 있다.

제목) 정보분배/SQLite/Cache/Redis/WebHttp/Manual Program

1. 정보분배 TCP데이타 제공처(KRX)
증권정보데이타(Securities Information Data)는 주식, 채권, 파생상품 등 다양한 금융 상품에 대한 정보를 제공하는 데이터입니다. 
이 데이터는 투자자, 금융 기관, 애널리스트 및 연구원들이 시장 동향을 파악하고 투자 결정을 내리는 데 중요한 역할을 합니다.
주식 데이터:
가격 정보: 시가, 종가, 고가, 저가, 거래량, 거래대금 등.
주식 지표: PER(주가수익비율), PBR(주가순자산비율), EPS(주당순이익) 등.
파생상품 데이터:
선물/옵션 정보: 기초 자산, 만기일, 행사가격, 거래량 등.
파생상품 지표: 변동성, 델타, 감마, 세타 등 그릭스(Greeks) 값.
거래소 정보:
지수 정보: 종합주가지수, 섹터별 지수, 글로벌 지수 등.
시장 통계: 거래소 전체의 거래량, 거래대금, 상장 종목 수 등.
데이터 제공 방법
실시간 데이터: 거래소와 데이터 제공업체가 실시간으로 업데이트되는 데이터를 제공합니다.
주요 제공 업체
한국거래소: 국내 주식, 채권, 파생상품의 거래 데이터를 제공합니다.
증권정보데이타는 금융 시장 참여자들이 시장을 이해하고 효과적으로 대응할 수 있도록 돕는 중요한 도구입니다. 

프로그램 테스트를 위한 과거데이타 전송)

2. Manual Program(직접만든프로그램) - mdimmmcache.exe

2.1 정보분배 TCP데이타 수신(21111 포트)
2.2 정보분배 TCP데이타를 SQLite DB에 저장(파일저장)
2.3 정보분배 TCP데이타를 Web Browser의 Request에 Response 응답(JSON데이타 포맷) - 8080포트
2.4 정보분배 TCP데이타를 Manual Program - sendrcvredis.exe 의 Request에 Response 응답(JSON데이타 포맷)
- 6379포트

비고) SendMessage를 이용한 Debugging(Windows에서 SendMessage를 이용해서 로그를 보는것이 편하다.)


비고) Web Browser에서 Request시에, JSON포맷으로 Response 받는예.


3. SQLite DataBase
SQLite는 가벼운 디스크 기반 데이터베이스 관리 시스템(DBMS)입니다. 
여기서 "가벼운"은 소프트웨어의 크기와 자원 소비가 적다는 것을 의미합니다. 
SQLite는 서버 기반 DBMS와 달리 클라이언트-서버 구조가 아닌 내장형 데이터베이스로, 어플리케이션에 직접 통합됩니다.

주요 특징
독립형:

SQLite는 단일 파일로 모든 데이터베이스를 저장합니다. 이는 배포와 백업을 간단하게 만듭니다.
제로 설정:
설치나 초기 설정이 필요 없습니다. SQLite 라이브러리 파일을 어플리케이션에 포함시키면 바로 사용할 수 있습니다.
서버리스:
별도의 서버 프로세스가 필요 없습니다. 어플리케이션이 직접 SQLite 데이터베이스 파일을 읽고 쓸 수 있습니다.
크로스 플랫폼:
다양한 운영체제에서 동작하며, 동일한 데이터베이스 파일이 여러 플랫폼에서 호환됩니다.
높은 신뢰성:
SQLite는 트랜잭션을 지원하며, ACID(Atomicity, Consistency, Isolation, Durability) 속성을 보장합니다.
표준 SQL 지원:
대부분의 SQL-92 표준을 지원합니다. 하지만 몇 가지 고급 기능은 지원하지 않을 수 있습니다.
사용 사례
임베디드 시스템:
모바일 장치, IoT 기기, 가전제품 등에서 많이 사용됩니다.
테스트 및 프로토타이핑:
서버 기반 DBMS의 복잡성을 피하기 위해 초기 개발 단계에서 사용됩니다.
데스크탑 응용 프로그램:
여러 데스크탑 애플리케이션에서 데이터 저장을 위해 사용됩니다.
웹 브라우저:
브라우저 내부에서 사용자의 데이터를 저장하기 위해 사용됩니다. 예: Google Chrome, Firefox의 내부 데이터 저장.
장단점
장점:
매우 가볍고 빠릅니다.
설정이 간단하고 사용이 편리합니다.
소스 코드가 공개되어 있어 수정 및 커스터마이징이 가능합니다.
파일 기반이므로 이동성과 백업이 용이합니다.
단점:
동시성이 필요한 대규모 애플리케이션에서는 성능이 떨어질 수 있습니다.
고급 기능(예: 저장 프로시저, 사용자 정의 함수 등)이 부족할 수 있습니다.
대용량 데이터를 처리하는 데는 적합하지 않을 수 있습니다.



4. REDIS
Redis는 오픈 소스 인메모리 데이터 구조 저장소로, 주로 고성능의 실시간 애플리케이션을 위해 사용됩니다. 
Redis는 "Remote Dictionary Server"의 약자로, 다양한 데이터 구조를 지원하며, 높은 속도와 확장성을 제공하는 것이 특징입니다.

주요 특징
인메모리 데이터베이스:
Redis는 데이터를 메모리에 저장하므로 매우 빠른 읽기 및 쓰기 속도를 제공합니다. 디스크에도 비동기적으로 데이터를 저장할 수 있어 내구성을 보장합니다.
다양한 데이터 구조 지원:
문자열, 리스트, 셋(set), 해시(hash), 정렬된 셋(sorted set), 비트맵(bitmap), 하이퍼로그로그(hyperloglog), 지오스페이셜 인덱스(geospatial index) 등의 다양한 데이터 구조를 지원합니다.
퍼시스턴스:
데이터를 디스크에 저장하여 메모리에서 데이터가 손실되는 것을 방지할 수 있습니다. RDB(Snapshotting)와 AOF(Append Only File) 두 가지 방식으로 퍼시스턴스를 제공합니다.
사용 사례
캐싱:빠른 데이터 액세스를 위해 자주 사용되는 데이터를 캐시합니다.
세션 저장소:웹 애플리케이션의 사용자 세션 데이터를 저장합니다.
실시간 분석:실시간 로그 처리 및 데이터 분석에 사용됩니다.
메시지 큐:Pub/Sub 메시징 시스템을 통해 메시지 큐로 사용할 수 있습니다.
장점:
매우 빠른 속도와 낮은 지연 시간.
다양한 데이터 구조 지원.
높은 가용성과 확장성.
단순하고 직관적인 API.
단점:
메모리에 데이터를 저장하므로 메모리 용량에 제한이 있음.



6. Manual Program(직접만든프로그램) - sendrcvredis.exe

REDIS PUSH/POP을 테스트할수 있는 프로그램

+ Recent posts