C#에서 클래스를 생성할 때 new 키워드(먼저 코드 훑어보기)


C#에서 클래스를 생성할 때 new 키워드를 사용하는 것은 객체 지향 프로그래밍의 기본적인 개념과 관련이 있습니다. 하지만 언어학적인 측면에서 C#의 이러한 특징은 몇 가지 중요한 이유와 관련이 있습니다:

  1. 명시적 객체 생성: new 키워드를 사용함으로써 객체를 명시적으로 생성하는 방식은 C#에서 객체 지향 프로그래밍의 기본 원칙 중 하나인 명확성과 직관성을 제공합니다. 이는 객체가 생성되고 메모리가 할당되는 순간을 코드에서 분명히 나타내어, 객체의 생명 주기를 명확히 관리할 수 있게 합니다.
  2. 메모리 관리: C#은 가비지 컬렉션(Garbage Collection)을 사용하는 언어입니다. new 키워드를 사용하여 객체를 생성하면, 해당 객체는 힙(Heap) 메모리에 할당되며, 가비지 컬렉터가 이를 관리합니다. 이는 메모리 누수 방지와 효율적인 메모리 관리를 가능하게 합니다.
  3. 형식 안정성: C#은 강타입 언어로, 변수의 형식이 엄격히 검증됩니다. new 키워드를 사용함으로써, 컴파일 타임에 타입의 정확성을 보장받을 수 있습니다. 이는 형식 안전성을 유지하고, 코드의 버그를 사전에 방지하는 데 도움을 줍니다.
  4. 생성자 호출: new 키워드를 사용하면 클래스의 생성자가 호출됩니다. 생성자는 객체의 초기 상태를 설정하는 역할을 하며, 이는 객체를 사용할 준비가 되었다는 것을 보장합니다. 생성자의 호출은 클래스의 초기화와 관련된 중요한 언어적 특성입니다.
  5. 명시적 인스턴스화: new 키워드를 사용하여 객체를 생성하는 방식은 클래스의 인스턴스화가 명시적임을 의미합니다. 이는 코드에서 객체가 언제, 어떻게 생성되는지를 명확히 이해할 수 있게 도와줍니다.
  6. 객체 지향 패러다임: C#은 객체 지향 프로그래밍(OOP)을 기반으로 한 언어입니다. new 키워드는 OOP의 기본 원칙을 따르며, 객체 지향 설계에서 중요한 역할을 하는 객체 생성과 초기화 과정을 관리하는 방식으로, 언어의 구조와 설계 철학을 반영합니다.

따라서, C#에서 new 키워드를 사용하여 클래스를 생성하는 것은 단순히 메모리 할당의 수단이 아니라, 언어의 구조와 객체 지향 패러다임, 메모리 관리, 형식 안정성 등 여러 언어적 특징과 관련이 있습니다.

public static CodeLengthInfo findCodeArrayIndexInfo(string code)
{
    CodeLengthInfo info = new CodeLengthInfo();
    List<string> strList = new List<string>();

    for(int kk=0; kk<krxdetailformat.GetLength(0); kk++)
    {
        if(krxdetailformat[kk,0] == code)
        {
            strList.Add(krxdetailformat[kk,9]);
        }
    }
    
    int arraysum = 0;
    info.arrayIndex = new int[strList.Count];

    for(int kk=0; kk<strList.Count; kk++)
    {
        arraysum = arraysum + Convert.ToInt32(strList[kk]);
info.arrayIndex[kk] = Convert.ToInt32(strList[kk]);

    }
    info.arraysum = arraysum;
    info.code = code;

    return info;
}
public struct CodeLengthInfo
{
        public string code;
        public int arraysum;
        public int[] arrayIndex;
}

 

메소드에 static 키워드를 사용하는 이유는 여러 가지가 있습니다. static 메소드는 클래스의 인스턴스(즉, 객체)를 생성하지 않고도 호출할 수 있는 메소드입니다. 아래는 static 메소드를 사용하는 주요 이유들입니다:

  1. 인스턴스와 무관한 기능: static 메소드는 클래스의 인스턴스 상태에 의존하지 않고, 클래스 자체의 상태에만 의존합니다. 위의 findCodeArrayIndexInfo 메소드는 특정 코드에 대한 정보를 찾는 기능을 수행하고 있으며, 이 메소드는 클래스의 인스턴스 상태에 의존하지 않기 때문에 static으로 선언되었습니다. 이는 메소드가 클래스 레벨에서 독립적으로 동작할 수 있음을 의미합니다.
  2. 메모리 절약: static 메소드는 클래스가 메모리에 로드될 때 한 번만 생성되며, 클래스의 모든 인스턴스가 이 메소드를 공유합니다. 이는 메모리 사용을 최적화하는 데 도움이 됩니다. 인스턴스 메소드는 각 객체마다 별도로 존재하지만, static 메소드는 클래스당 하나만 존재합니다.
  3. 유틸리티 메소드: static 메소드는 일반적으로 유틸리티 메소드로 사용됩니다. 유틸리티 메소드는 주로 데이터 변환, 계산 또는 기타 공통 작업을 수행하며, 클래스의 특정 상태나 인스턴스 변수에 접근할 필요가 없습니다. findCodeArrayIndexInfo 메소드도 이러한 유틸리티 메소드의 예로 볼 수 있습니다.
  4. 편리한 접근: static 메소드는 클래스 이름을 통해 직접 호출할 수 있으므로, 객체를 생성하지 않고도 메소드에 접근할 수 있습니다. 예를 들어, MyClass.findCodeArrayIndexInfo(code)처럼 호출할 수 있습니다. 이는 간편하게 메소드를 사용할 수 있는 방법을 제공합니다.
  5. 성능: static 메소드는 객체 생성 비용을 줄이고, 직접 호출할 수 있기 때문에 성능 측면에서 유리할 수 있습니다. 객체를 생성하지 않고도 메소드를 호출할 수 있으므로, 특정 상황에서는 성능 향상을 가져올 수 있습니다.

따라서 findCodeArrayIndexInfo 메소드가 static으로 정의된 이유는 해당 메소드가 특정 인스턴스 상태에 의존하지 않고, 클래스 수준에서 독립적으로 동작하기 때문입니다.

 

C#과 Java에서 배열 선언 및 사용에 차이점이 몇 가지 있습니다. 주요 차이점을 아래에 정리해 보았습니다.

1. 배열 선언 방식

  • C#: Type[] arrayName = new Type[size];
  • Java: Type[] arrayName = new Type[size];

배열 선언 방식은 C#과 Java 모두 유사하지만, 배열 초기화 방법에 따라 차이가 있을 수 있습니다.

2. 배열 크기 지정

  • C#: 배열을 선언할 때 크기를 지정하지 않고 초기화할 수 있습니다.
    csharp
    int[] numbers = { 1, 2, 3 };
  • Java: 배열 선언 시 크기나 값을 바로 할당할 수 있습니다.
    java
    int[] numbers = { 1, 2, 3 };

3. 배열 초기화 값

  • C#: 배열이 선언되면 자동으로 기본값으로 초기화됩니다. 예를 들어, int 배열의 경우 모든 값이 0으로 초기화됩니다.
  • Java: Java에서도 배열은 선언되면 자동으로 기본값으로 초기화됩니다. int 배열은 0, boolean 배열은 false로 초기화됩니다.

4. 배열 속성

  • C#: 배열의 길이를 확인할 때 Length 속성을 사용합니다.
    csharp
    int[] numbers = new int[3]; int length = numbers.Length;
  • Java: Java에서는 length 필드를 사용합니다.
    java
    int[] numbers = new int[3]; int length = numbers.length;

5. 다차원 배열

  • C#: 다차원 배열을 쉽게 선언할 수 있으며, 직사각형 배열과 가변 배열(혹은 계단식 배열)을 지원합니다.
    csharp
    // 직사각형 배열 int[,] matrix = new int[3, 3]; // 가변 배열 (계단식 배열) int[][] jaggedArray = new int[3][]; jaggedArray[0] = new int[2]; jaggedArray[1] = new int[3]; jaggedArray[2] = new int[1];
  • Java: Java에서는 다차원 배열을 가변 배열(계단식 배열)로만 선언할 수 있습니다.
    java
    int[][] matrix = new int[3][]; matrix[0] = new int[2]; matrix[1] = new int[3]; matrix[2] = new int[1];

6. Array 클래스 지원

  • C#: 배열은 System.Array 클래스를 상속받아 여러 가지 메서드를 제공합니다. 예를 들어 Array.Sort(), Array.Reverse() 등을 사용할 수 있습니다.
  • Java: Java 배열은 java.util.Arrays 클래스를 통해 다양한 유틸리티 메서드 (Arrays.sort(), Arrays.toString())를 사용할 수 있습니다.

7. 형식 안전성

  • C#: C#에서는 배열에 형식 안전성이 강화되어 있어 선언된 형식과 일치하지 않는 데이터를 추가할 수 없습니다.
  • Java: Java에서도 마찬가지로 배열 선언 시 지정된 형식 외의 데이터는 허용되지 않습니다.

이처럼 C#과 Java는 배열 선언 및 처리 방식에서 유사한 점이 많지만, 세부적인 기능과 문법에서는 차이가 있습니다.

 

1. 속성창 수정안하고, 코드에서 부르기
새 콘솔 창 생성하기
또 다른 방법으로는 프로그램 실행 중에 콘솔 창을 동적으로 생성하는 방법이 있습니다.

[System.Runtime.InteropServices.DllImport("kernel32.dll")]
private static extern bool AllocConsole();

public Form1()
{
    InitializeComponent();
    
    AllocConsole();
    
    Console.WriteLine("이것은 콘솔 창에 출력됩니다.");
}


2. 프로젝트 설정 변경하기

C# Windows Forms 애플리케이션에서 Console.WriteLine()을 사용하여 명령 프롬프트 창에 메시지를 출력하려면, 프로젝트 설정을 변경하여 애플리케이션을 "콘솔 애플리케이션"으로 설정해야 합니다. 이렇게 하면 Windows Forms 애플리케이션이 실행될 때 콘솔 창이 함께 나타나고, Console.WriteLine()으로 메시지를 출력할 수 있습니다.

방법 1: 프로젝트 설정 변경하기

  1. Visual Studio에서 Windows Forms 프로젝트를 엽니다.
  2. 솔루션 탐색기에서 프로젝트를 마우스 오른쪽 버튼으로 클릭하고, "속성"을 선택합니다.
  3. "애플리케이션" 탭에서 "출력 형식"을 콘솔 응용 프로그램으로 변경합니다.

1. Redis를 이용한 실시간 push데이타 전송(서버측)
2. Redis를 이용한 실시간 push데이타 수신(클라이언트측)

1. Redis를 이용한 실시간 push데이타 전송(서버측)
1.1 KRX 정보분배 데이타를 수신후 서버측에서 파싱
1.2 클라이언트 로그인처리, 로그인키와 로그인 시간등
1.3 서버측에서 파싱후, 로그인되어진 클라이언트키로 Redis에 각각 Json포맷 데이타 전송
1.4 조회부분도 마찬가지

2. Redis를 이용한 실시간 push데이타 수신(클라이언트측)
2.1 서버측에 로그인키전달(DebugNumber + RedisServerAddress + RedisServerPort + ClientAddress)
2.2 Redis에 로그인키로 POP 연속적으로 수신
2.3 조회도 마찬가지

결론)
Redis를 이용한 실시간 push데이타 전송 & 수신은
서버측에서 클라이언트에 직접 데이타 전송과 마찬가지의 효과를 얻는다.

 

CodePagesEncodingProvider 사용 예제

CodePagesEncodingProvider를 사용하는 방법은 다음과 같습니다. 이 방법은 EUC-KR을 포함한 다양한 코드 페이지를 지원합니다.

  • EUC-KR 인코딩: C#에서는 Encoding.GetEncoding("euc-kr")를 통해 EUC-KR 인코딩을 사용할 수 있습니다. 그러나, euc-kr이 지원되지 않는 환경에서는 다른 방법을 사용해야 할 수 있습니다. 이 경우, CodePagesEncodingProvider를 추가하여 EUC-KR을 지원할 수 있습니다.
  • 버퍼 크기: UTF-8 인코딩은 가변 길이 문자 인코딩이므로, 변환 후 버퍼의 크기를 적절히 관리해야 합니다.
using System;
using System.Text;

class Program
{
    static void Main()
    {
        // EUC-KR 인코딩 제공자를 등록
        Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

        // 예제 EUC-KR 인코딩된 바이트 데이터
        byte[] eucKrBytes = new byte[] { /* EUC-KR로 인코딩된 바이트 데이터 */ };

        // EUC-KR 인코딩으로 바이트 배열을 문자열로 변환
        Encoding eucKrEncoding = Encoding.GetEncoding("euc-kr");
        string eucKrString = eucKrEncoding.GetString(eucKrBytes);

        // 문자열을 UTF-8 인코딩으로 변환
        Encoding utf8Encoding = Encoding.UTF8;
        byte[] utf8Bytes = utf8Encoding.GetBytes(eucKrString);

        // UTF-8 바이트 배열을 문자열로 변환
        string utf8String = utf8Encoding.GetString(utf8Bytes);

        // 결과 출력
        Console.WriteLine("EUC-KR String: " + eucKrString);
        Console.WriteLine("UTF-8 String: " + utf8String);
    }
}




KRX.TCP.DATA - EUC-KR로 전달되어짐
c#이 서버역할을 할떄에 EUC-KR필드만 따로 분리해서 처리해야 한다.(예, 한글종목코드)

Redis는 클라이언트의 연결 수를 제한하는 기능을 제공합니다. 이를 통해 Redis 서버가 과도한 연결로 인해 리소스가 소모되는 것을 방지할 수 있습니다. 기본적으로 Redis는 클라이언트 연결 수에 대한 제한을 설정하지 않지만, 몇 가지 방법으로 이를 조정할 수 있습니다:

  1. maxclients 설정: Redis의 설정 파일(redis.conf)에서 maxclients 옵션을 사용하여 허용할 최대 클라이언트 연결 수를 설정할 수 있습니다. 예를 들어, maxclients 10000이라고 설정하면 최대 10,000개의 클라이언트가 동시에 연결될 수 있습니다. 이 값은 Redis 서버의 메모리와 시스템의 자원에 따라 조정해야 합니다.
  2.  
    maxclients 10000
  3. 운영 체제의 파일 핸들 제한: Redis는 운영 체제의 파일 핸들 수에 따라 제한을 받을 수 있습니다. Redis는 각 클라이언트 연결을 파일 핸들로 처리하므로, 운영 체제에서 허용하는 파일 핸들의 수에 따라 Redis의 최대 연결 수가 제한될 수 있습니다. 이를 조정하려면 운영 체제의 설정을 변경해야 합니다. 예를 들어, Linux에서는 ulimit 명령어를 사용하여 파일 핸들 수를 조정할 수 있습니다.
  4.  
    ulimit -n 10000
  5. 클라이언트 연결 수의 모니터링: Redis 서버의 연결 상태를 모니터링하는 것도 중요합니다. INFO clients 명령어를 사용하여 현재 연결된 클라이언트의 수를 확인할 수 있습니다.
  6.  
    INFO clients
  7. client-output-buffer-limit 설정: Redis는 클라이언트의 출력 버퍼가 너무 커지는 것을 방지하기 위해 client-output-buffer-limit 설정을 제공합니다. 이 설정은 클라이언트가 보내는 데이터의 크기를 제한하여 서버가 과도한 메모리를 소비하지 않도록 합니다.
  8.  
    client-output-buffer-limit pubsub 33554432 8388608 60

Redis 서버의 연결 제한을 적절히 설정하면 성능을 안정적으로 유지할 수 있으며, 시스템 자원을 효율적으로 관리할 수 있습니다.

Linux에서 C# 프로젝트를 설정하고 빌드하는 과정은 다음과 같습니다. 이 과정에서는 .NET Core 또는 .NET 5/6/7 SDK를 사용하여 C# 프로젝트를 설정하고 빌드합니다. 이 가이드는 Ubuntu 시스템을 기준으로 작성되었습니다.

1. .NET SDK 설치

패키지 목록 업데이트 및 필수 패키지 설치
sudo apt update
sudo apt install -y wget apt-transport-https software-properties-common
wget https://packages.microsoft.com/keys/microsoft.asc
sudo apt-key add microsoft.asc
sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/ubuntu/20.04/prod focal main" > /etc/apt/sources.list.d/dotnetdev.list'

.NET SDK 설치
sudo apt update
sudo apt install -y dotnet-sdk-7.0

설치 확인
dotnet --version

2. C# 프로젝트 생성
dotnet new console -o MyConsoleApp
이 명령어는 MyConsoleApp이라는 새 폴더를 생성하고 그 안에 C# 콘솔 애플리케이션 프로젝트를 생성합니다.
dotnet new console -o mdiwebrowser


프로젝트 디렉토리로 이동

프로젝트 빌드 및 실행

프로젝트 빌드
dotnet build


1. Systehttp://m.Data.SQLite 라이브러리 추가
2. Newtonsoft.Json 라이브러리 추가
3. ServiceStack.Redis 라이브러리 추가

1. Systehttp://m.Data.SQLite 라이브러리 추가
dotnet add package Systehttp://m.Data.SQLite
2. Newtonsoft.Json 라이브러리 추가
dotnet add package Newtonsoft.Json
3. ServiceStack.Redis 라이브러리 추가
dotnet add package ServiceStack.Redis

프로젝트 실행
dotnet run

TCP 연결 종료 과정 (4-way handshake)

C:\Users\B210145_BK\Downloads\exture_3_5_ubuntu_ticker\send>netstat -an | findstr 21111
  TCP    0.0.0.0:21111          0.0.0.0:0              LISTENING
  TCP    127.0.0.1:52028        127.0.0.1:21111        TIME_WAIT
  TCP    127.0.0.1:52039        127.0.0.1:21111        TIME_WAIT
  TCP    127.0.0.1:52041        127.0.0.1:21111        TIME_WAIT
  TCP    127.0.0.1:52042        127.0.0.1:21111        TIME_WAIT
  TCP    127.0.0.1:52043        127.0.0.1:21111        TIME_WAIT
  TCP    127.0.0.1:52044        127.0.0.1:21111        TIME_WAIT
  TCP    127.0.0.1:52045        127.0.0.1:21111        TIME_WAIT
  TCP    127.0.0.1:52047        127.0.0.1:21111        TIME_WAIT
  TCP    127.0.0.1:52048        127.0.0.1:21111        TIME_WAIT
  TCP    127.0.0.1:52049        127.0.0.1:21111        TIME_WAIT
  TCP    127.0.0.1:52050        127.0.0.1:21111        TIME_WAIT
  TCP    127.0.0.1:52054        127.0.0.1:21111        TIME_WAIT
  TCP    127.0.0.1:52059        127.0.0.1:21111        TIME_WAIT
  TCP    127.0.0.1:52060        127.0.0.1:21111        TIME_WAIT
  TCP    127.0.0.1:52062        127.0.0.1:21111        TIME_WAIT
  TCP    127.0.0.1:52064        127.0.0.1:21111        TIME_WAIT
  TCP    127.0.0.1:52065        127.0.0.1:21111        TIME_WAIT
  TCP    127.0.0.1:52066        127.0.0.1:21111        TIME_WAIT
  TCP    127.0.0.1:52067        127.0.0.1:21111        TIME_WAIT
  TCP    127.0.0.1:52068        127.0.0.1:21111        TIME_WAIT
  TCP    127.0.0.1:52069        127.0.0.1:21111        TIME_WAIT
  TCP    127.0.0.1:52070        127.0.0.1:21111        TIME_WAIT
  TCP    127.0.0.1:52071        127.0.0.1:21111        TIME_WAIT
  TCP    127.0.0.1:52072        127.0.0.1:21111        TIME_WAIT

TIME_WAIT 상태가 발생하는 이유는 TCP 연결이 정상적으로 종료될 때 클라이언트 또는 서버가 잠시 동안 연결을 유지하는 과정에서 발생합니다. 이 상태는 연결이 완전히 종료되기 전에 남아있는 패킷들이 네트워크에서 잘못 전달되는 것을 방지하고, 이전에 사용된 소켓 번호가 재사용될 때 발생할 수 있는 문제를 방지하기 위해 설계되었습니다.

TCP 연결 종료 과정 (4-way handshake):

  1. FIN_WAIT-1: 클라이언트가 연결 종료를 요청하며 FIN 패킷을 전송합니다.
  2. CLOSE_WAIT: 서버가 FIN 패킷을 받고 ACK(확인 응답)를 보냅니다.
  3. FIN_WAIT-2: 서버가 연결 종료를 요청하며 FIN 패킷을 전송합니다.
  4. TIME_WAIT: 클라이언트가 서버로부터 FIN 패킷을 받고, ACK를 보낸 후 일정 시간 동안 기다립니다.


    TIME_WAIT 상태가 생기는 이유:
    1. 잔여 패킷 방지: 네트워크에서 늦게 도착한 패킷이 새로운 연결에 영향을 주지 않도록 하기 위해, TCP는 TIME_WAIT 상태를 유지하여 그 연결에 대한 패킷이 모두 소진되었음을 확인합니다.
    2. 포트 재사용 방지: 동일한 소켓 번호(포트)를 사용하는 새 연결이 바로 발생할 경우, 이전 연결의 잔여 패킷이 새 연결에 영향을 줄 수 있습니다. TIME_WAIT 상태는 이러한 상황을 방지하는 역할을 합니다.
    기본적으로 TIME_WAIT 상태는 일정 시간이 지나면 자동으로 종료되며, 이는 운영체제에 따라 다를 수 있습니다(일반적으로 2배의 Maximum Segment Lifetime, MSL). TIME_WAIT 상태가 너무 많으면 시스템의 소켓 리소스를 소모할 수 있지만, 이는 TCP 프로토콜의 정상적인 동작의 일환이므로 필요 이상으로 걱정할 필요는 없습니다.

Title) Multi HomeTrade & Redis Connect & Data Request - Response

HomeTrade(1) - LOGIN -> Private QueueName Send - (212700163791921682149)

HomeTrade(2) - LOGIN -> Private QueueName Send - (112700163791921682149)


DIAGRAM.BASIC LOGIN

 

 

Linux에서)

1. 리눅스 종류

sinfo@sinfo:~$ uname -a
Linux sinfo 5.4.0-192-generic #212-Ubuntu SMP Fri Jul 5 09:47:39 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux

2. 네트워크 연결상태

sinfo@sinfo:~$ netstat -an | grep 21111
tcp        0      0 0.0.0.0:21111           0.0.0.0:*               LISTEN
tcp        0      0 192.168.45.48:21111     192.168.45.106:50236    ESTABLISHED
tcp        0      0 192.168.45.48:21111     192.168.45.106:50232    ESTABLISHED
sinfo@sinfo:~$ netstat -an | grep 6379
tcp        0      0 0.0.0.0:6379            0.0.0.0:*               LISTEN
tcp        0      0 192.168.45.48:6379      192.168.45.106:50237    ESTABLISHED
tcp        0      0 127.0.0.1:6379          127.0.0.1:44420         ESTABLISHED
tcp        0      0 127.0.0.1:6379          127.0.0.1:45878         ESTABLISHED
tcp        0      0 192.168.45.48:6379      192.168.45.106:50243    ESTABLISHED
tcp        0      0 192.168.45.48:6379      192.168.45.106:50233    ESTABLISHED
tcp        0      0 127.0.0.1:45878         127.0.0.1:6379          ESTABLISHED
tcp        0      0 127.0.0.1:44420         127.0.0.1:6379          ESTABLISHED
sinfo@sinfo:~$

3. 프로세스 확인

sinfo@sinfo:~$ ps -ef | grep redis
redis       1056       1  0 21:36 ?        00:00:13 /usr/bin/redis-server 0.0.0.0:6379
sinfo       5828    5350  0 23:02 pts/1    00:00:00 grep --color=auto redis
sinfo@sinfo:~$ ps aux | grep dotnet
sinfo       5538  1.2  2.6 274724316 215040 pts/0 Sl  22:53   0:07 /usr/share/dotnet/dotnet exec /usr/share/dotnet/sdk/7.0.410/Roslyn/bincore/VBCSCompiler.dll -pipename:MhsDIaqs8oyke8Na2IDl4QN9EwVUpE+Cpyfj50fyAN4
sinfo       5676  0.5  2.0 274830744 163780 pts/0 Sl+ 22:56   0:02 dotnet run
sinfo       5844  0.0  0.0   6432   720 pts/1    S+   23:03   0:00 grep --color=auto dotnet
sinfo@sinfo:~$ ps aux | grep mdi
sinfo       5706  0.3  1.3 274329620 112340 pts/0 Sl+ 22:56   0:01 /data/sinfo/exture_3_0_ticker/mdiwebrowser/bin/Debug/net7.0/mdiwebrowser
sinfo       5852  0.0  0.0   6300   656 pts/1    S+   23:03   0:00 grep --color=auto mdi
sinfo@sinfo:~$


4. 클라이언트는 Windows////////

 

GetInstance를 활용한 List<string> 예제,ㅡㅡㅡ,ㅡㅡㅡ
GetInstance를 활용한 List<string> 예제,ㅡㅡㅡ,ㅡㅡㅡ

public List<string> redisSenderQueueNM

using System;
using System.Collections.Generic;

public class APMMemory
{
    private static APMMemory apmMemory;
    private List<string> redissenderqueuenm = new List<string>();

    public List<string> redisSenderQueueNM
    {
        get { return redissenderqueuenm; }
        set { redissenderqueuenm = value; }
    }

    private APMMemory() { }

    public static APMMemory GetInstance
    {
        get
        {
            if (apmMemory == null)
                apmMemory = new APMMemory();
            return apmMemory;
        }
    }

    // 문자열을 추가할 때 중복을 체크하는 메서드
    public void AddQueueName(string queueName)
    {
        if (!redissenderqueuenm.Contains(queueName))
        {
            redissenderqueuenm.Add(queueName);
            Console.WriteLine($"Added: {queueName}");
        }
        else
        {
            Console.WriteLine($"Queue name '{queueName}' already exists and was not added.");
        }
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        // Singleton instance 가져오기
        APMMemory apmMemory = APMMemory.GetInstance;

        // 중복되지 않게 문자열을 리스트에 추가
        apmMemory.AddQueueName("Queue1");
        apmMemory.AddQueueName("Queue2");
        apmMemory.AddQueueName("Queue3");

        // 중복되는 문자열 추가 시도
        apmMemory.AddQueueName("Queue2");  // 이미 존재하는 문자열
        apmMemory.AddQueueName("Queue4");

        // redisSenderQueueNM 리스트 출력
        Console.WriteLine("\nFinal Redis Sender Queue Names:");
        foreach (string queueName in apmMemory.redisSenderQueueNM)
        {
            Console.WriteLine(queueName);
        }
    }
}

[A 경제용어사전] '베어마켓·불마켓(bear·bull market)'


황소(Bull)
황소 시장(Bull Market)은 주가가 전반적으로 상승하는 시장 상태를 나타내며, 이는 경제의 성장, 기업 실적 호조, 투자자들의 신뢰 증가 등으로 인해 발생합니다.
황소는 뿔을 위로 치켜들며 공격하는 습성 때문에 상승을 상징하게 되었습니다.
황소 시장에서는 투자자들이 적극적으로 주식을 매수하며, 이러한 매수세는 주가를 더욱 끌어올립니다.
역사적으로, '황소'는 19세기 초부터 금융가들 사이에서 사용되기 시작했습니다.
이 용어는 특히 뉴욕 증권거래소(NYSE)가 발달하면서 더욱 널리 퍼졌습니다.
황소 시장은 경제의 번영기와 맞물리며, 투자자들에게 높은 수익을 안겨주는 시기로 평가받습니다.

곰 (Bear)
곰은 증권시장에서 비관적인 분위기와 하락장을 상징합니다.
곰 시장(Bear Market)은 주가가 전반적으로 하락하는 시장 상태를 의미하며, 이는 경제 불황, 기업 실적 악화, 투자자들의 불안감 증가 등으로 인해 발생합니다.
곰은 발톱을 아래로 내리치는 습성 때문에 하락을 상징하게 되었습니다.
곰 시장에서는 투자자들이 주식을 매도하며, 이러한 매도세는 주가를 더욱 끌어내립니다.
'곰' 역시 19세기 초부터 금융가들 사이에서 사용되기 시작했습니다.
곰 시장은 경제의 불황기와 맞물리며, 투자자들에게 큰 손실을 안겨주는 시기로 평가받습니다.

 

(한국.거래소의 황소와 곰의 모습)

KRX 정보분배데이타,수신서버및 HomeTrade 제작

내용)

1. KRX 정보분배데이타 송신 SYSTEM 제작
2. KRX 정보분배데이타 수신 SYSTEM 제작
2.1 - KRX 정보분배데이타 수신
2.2 - KRX 정보분배데이타 저장(SQLite)
2.3 - KRX 정보분배데이타 REDIS전송
2.4 - 클라이언트 로그인 관리
2.5 - 클라이언트 조회요청시 데이타 전송
3. Like HomeTradeSystem - Win MDI Application
3.1 - 로그인
3.2 - 조회및 데이타 실시간수신
4. 디버깅 - Windows SendMessage 활용


기술)
1. KRX 정보분배데이타 송신 SYSTEM 제작 -> c
2. KRX 정보분배데이타 수신 SYSTEM 제작 -> c# Console
2.1 - KRX 정보분배데이타 수신
2.2 - KRX 정보분배데이타 저장(SQLite) - SQLite DataBase
2.3 - KRX 정보분배데이타 REDIS전송 - Redis Server
2.4 - 클라이언트 로그인 관리
2.5 - 클라이언트 조회요청시 데이타 전송
3. Like HomeTradeSystem - Win MDI Application - c# Win Form
3.1 - 로그인
3.2 - 조회및 데이타 실시간수신


MENU& TREE를 동시에 구성


일별.캔들차드 추가(feat. CHAT.GPT)

 

REDIS.QUEUE.NAME WHEN RCV/SND
REDIS.QUEUE.NAME WHEN RCV/SND

 


dotnet new wpf -n sampleNM

error CS0246: 'Newtonsoft' 형식또는 네임스페이스 이름을 찾을 수 없습니다. using 지시문 또는 어셈블리 참조가 있는지 확인하세요.
>dotnet add package Newtonsoft.Json

error CS0246: 'ServiceStack' 형식 또는 네임스페이스 이름을 찾을 수 없습니다. using 지시문 또는 어셈블리 참조가 있는지 확인하세요.
>dotnet add package ServiceStack

error CS0246: 'RedisClient' 형식 또는 네임스페이스 이름을 찾을 수 없습니다. using 지시문 또는 어셈블리 참조가 있는지 확인하세요.
>dotnet add package ServiceStack.Redis

KeyValuePair<TKey, TValue>는 C#에서 제공하는 구조체(struct)로, 키와 값을 쌍으로 묶어서 관리할 수 있게 해줍니다. 주로 컬렉션에서 특정 항목의 키와 값을 함께 다룰 때 사용됩니다.

주요 특징

  1. 제네릭 타입: KeyValuePair는 제네릭 타입으로, 키와 값의 데이터 타입을 지정할 수 있습니다. 예를 들어, KeyValuePair<int, string>는 정수형 키와 문자열 값을 가지는 쌍을 의미합니다.
  2. 구성: KeyValuePair는 두 개의 읽기 전용 속성, Key와 Value,으로 구성됩니다. Key는 쌍의 키를, Value는 쌍의 값을 나타냅니다.
  3. 불변성: KeyValuePair의 키와 값은 읽기 전용 속성으로 정의되어 있으며, 한 번 생성된 후에는 변경할 수 없습니다.

사용 예제

다음은 KeyValuePair를 사용하는 몇 가지 예제입니다.

1. 기본 사용

// KeyValuePair 생성 KeyValuePair<int, string> kvp = new KeyValuePair<int, string>(1, "Value"); // 키와 값에 접근 Console.WriteLine($"Key: {kvp.Key}, Value: {kvp.Value}");

2. Dictionary에서 사용

Dictionary 클래스는 내부적으로 KeyValuePair를 사용하여 키와 값을 저장합니다.

Dictionary<string, int> dictionary = new Dictionary<string, int>(); // 키와 값을 추가 dictionary.Add("Apple", 1); dictionary.Add("Banana", 2); // Dictionary의 모든 항목을 반복 foreach (KeyValuePair<string, int> kvp in dictionary) { Console.WriteLine($"Key: {kvp.Key}, Value: {kvp.Value}"); }

3. LINQ와 함께 사용

LINQ를 사용할 때 KeyValuePair를 반환하는 메서드를 사용할 수 있습니다.

var list = new List<KeyValuePair<string, int>>() { new KeyValuePair<string, int>("Apple", 1), new KeyValuePair<string, int>("Banana", 2), }; var result = list.Where(kvp => kvp.Value > 1); foreach (var kvp in result) { Console.WriteLine($"Key: {kvp.Key}, Value: {kvp.Value}"); }

이와 같이 KeyValuePair는 다양한 상황에서 유용하게 사용될 수 있으며, 특히 컬렉션과 관련된 작업에서 많이 활용됩니다.




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:~#

+ Recent posts