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. "애플리케이션" 탭에서 "출력 형식"을 콘솔 응용 프로그램으로 변경합니다.

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필드만 따로 분리해서 처리해야 한다.(예, 한글종목코드)

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);
        }
    }
}


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

 

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

 

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 DB저장(file)/(동기식)HttpListener Interface/
정보분배수신/SQLite DB저장(file)/(동기식)HttpListener Interface/
정보분배수신/SQLite DB저장(file)/(동기식)HttpListener Interface/

비고)
키워드를 사용하지 않고 HTTP 서버를 구현하는 방법을 보여드리겠습니다. 
이 경우, HttpListener를 사용하여 비동기 방식이 아닌 동기 방식으로 요청을 처리합니다. 
동기 방식은 코드가 요청을 처리하는 동안 다른 작업을 수행할 수 없으므로 서버의 응답 속도가 느려질 수 있습니다.


NuGet으로 Package를 설치시에, 최신버젼으로 빌드하시면 됩니다.
./packages/Newtonsoft.Json.13.0.3/lib/net45/Newtonsoft.Json.dll
./packages/Stub.Systehttp://m.Data.SQLite.Core.NetFramework.1.0.118.0/build/net45/x64/SQLite.Interop.dll
./packages/Stub.Systehttp://m.Data.SQLite.Core.NetFramework.1.0.118.0/lib/net45/System.Data.SQLite.dll

1. 전체도식을 그려본다

 


- HTTP 인터페이스를 위한 8080포트 Listen
xterm@DESKTOP-VVAIF4D MINGW64 ~/Downloads/tmp/exture_3_0_ticker/mdiwebrowser

$ netstat -an | grep 8080
  TCP    0.0.0.0:8080           0.0.0.0:0              LISTENING
  TCP    [::]:8080              [::]:0                 LISTENING
  TCP    [::1]:8080             [::1]:50463            CLOSE_WAIT
  TCP    [::1]:8080             [::1]:50493            ESTABLISHED
  TCP    [::1]:8080             [::1]:50496            ESTABLISHED
  TCP    [::1]:50463            [::1]:8080             FIN_WAIT_2
  TCP    [::1]:50493            [::1]:8080             ESTABLISHED
  TCP    [::1]:50496            [::1]:8080             ESTABLISHED

- 정보분배 TCP데이타를 받기위한 21111포트 Listen
xterm@DESKTOP-VVAIF4D MINGW64 ~/Downloads/tmp/exture_3_0_ticker/mdiwebrowser
$ netstat -an | grep 2111
  TCP    127.0.0.1:21111        0.0.0.0:0              LISTENING


2. 거래소정보분배 TCP데이타 수신및 저장(SQLite)

3. SQLite Browser에서 나타내봅니다.(상용)

3. 거래소정보분배 TCP데이타 인터페이스(HTTP통신) - 동기식(한번에 하나의 resquest를 처리한다.)

3.1 - Text 표시
3.2 - Json 표시

+ Recent posts