2026/04/01

javascript 비동기 호출 (async, await, Promise) 기본 예제

단순 조회만 하면, 아래 처럼 필요가 없지만,
조회 요청한 데이터가 출력될때까지, 대기를 해야 하고,
데이터를 확인후에만 다음 단계로 넘어가야 할때. 주로 사용.

function checkValid(x) {
    return new Promise(function(resolve) {

        $.ajax({
            type: "POST",
            url: "/api/",
            data: JSON.stringify({ "x": x }),
            contentType: "application/json",
            dataType: "json",
          beforeSend: function () {
            // 필요하면 로딩 표시 시작
            // showLoading();
          },
success: function (data) { resolve(true);    // 성공시 }, error: function () { resolve(false);    // 실패, 에러 },
          complete: function () {
            // 필요하면 로딩 숨김
            // hideLoading();
          }
});

// 여러개 ajax 항목 동시 실행
}); }

async function saveOrSubmit() {
    const isValid = await checkValid(x);

    if (!isValid) {
        return;                    // 검증 실패하면 종료
    }
console.log("모든 검증 완료 → 실제 저장/처리 로직 실행"); proceedToNextStep(); // 또는 저장 AJAX 호출 등 }

$("#btn").click(function() {
    saveOrSubmit();
});


그런데, 위는 여러개 동시 호출방식이고,  단순하게 절차 단계마다 체크가 필요한 경우에는, async await 를 사용하는게 훨씬 더 직관적임. 

async function check(){}

//호출하는 함수도 async 설정 필요
const
isValid = await check(value);
 if (!isValid) {
        alert('유효하지 않습니다.');
        return;   // 중단
    }


form submit 이 bootstrap validator 플러그인에 바인딩되는 경우.

// 1. 초기화만 심플하게 해줍니다.
$("#form1").validator();

// 2. Submit 핸들러 하나로 통합 관리
$("#form1").on("submit", async function (e) {
    
    // 💡 부트스트랩 validator 검증에 실패한 경우
    if (e.isDefaultPrevented()) {
        // [수정] 버튼을 누를 때마다 무조건 Notify가 실행됩니다.
        $.notify(
            { message: "허용된 값이 아닙니다." },
            { type: "warning" }
        );
        return; // 더 이상 진행하지 않고 중단
    }

    // 부트스트랩 검증을 통과한 경우에만 아래 커스텀 로직 진행
    e.preventDefault(); 

    // 체크박스 검증
    if (!$("#usingAgree").is(":checked")) {
        alert("개인정보 수집/이용에 동의해야 합니다.");
        return;
    }

    // 비동기 검증
    if (!(await check(value))) {
        alert("유효하지 않습니다.");
        return; 
    }

    // 모든 검증 완료 -> 실제 서버로 전송
    e.target.submit(); 
});





2024/01/20

KB5034439 설치 오류 0x8024200B

업데이트 적용 환경 : Windows Server 2022 Std, 21H2

설치 실패: 0x8024200B 오류 때문에 Windows에서 다음 업데이트를 설치하지 못했습니다. 2024-01 x64 기반 시스템용 Microsoft server operating system version 21H2 보안 업데이트(KB5034439).

윈도우 10 2024년 1월 보안 업데이트(KB5034441)
윈도우 11 2024년 1월 보안 업데이트(KB5034440) 

# for hex 0x8024200b / decimal -2145116149
  WU_E_UH_INSTALLERFAILURE                                       wuerror.h
# The installer failed to install (uninstall) one or more
# updates.
# as an HRESULT: Severity: FAILURE (1), FACILITY_WINDOWSUPDATE (0x24), Code 0x200b
# for hex 0x200b / decimal 8203
  ERROR_DS_INVALID_ATTRIBUTE_SYNTAX                              winerror.h
# The attribute syntax specified to the directory service is
# invalid.
# 2 matches found for "0x8024200B"


https://answers.microsoft.com/en-us/windowserver/forum/all/windows-update-failure-on-january-9-2024kb5034129/61af6d50-1f7d-4863-8efb-46869f65885c


이번 업데이트 버그...?
디스크 복구 파티션 때문..?


구글 Blogger, 작성하신 블로그(제목: 'http://.blogspot.com/')가 삭제되었습니다


구글... 도대체 뭐하는 짓인지......??

뭐 내용상으로는,. 누군가 Spam 이라며 신고했다는 건데, 스팸 사이트도 아니고 그럴 내용도 없다. 누군가 악의적으로 신고한것인지 ? 아니면 구글 시스템 오류인건지?

특이한건,. 같은 구글 계정으로 생성된 블로그 3개가 동시에 같은 시간에 정지되었고(내용이 없는 블로그도 삭제됨 > 내용이 없는데 어떻게 스팸? 어이 없음), 해제 요청 후 약 10분만에 3개 모두 복구되었음.

이런식이면, 안정적으로 어떻게 이용할수 있겠는가...??


2024. 1. 18. 오전 5:23

안녕하세요, 아시고 계신 바와 같이 Blogger 커뮤니티 가이드(https://blogger.com/go/contentpolicy)에는 Blogger에서 허용되는 콘텐츠와 허용되지 않는 콘텐츠에 대한 설명이 안내되어 있습니다. 작성하신 블로그(제목: 'http://bitsyrup.blogspot.com/')에 대한 검토를 요청하는 신고가 접수되었습니다. 블로그가 Blogger 커뮤니티 가이드를 위반한 것으로 판단되어 블로그 독자가 해당 URL(http://bitsyrup.blogspot.com/)을 볼 수 없도록 조치했습니다. 블로그가 삭제된 이유 Google SPAM 정책을 위반한 콘텐츠입니다. 자세한 내용은 이메일에 링크된 커뮤니티 가이드 페이지에서 확인하세요. 블로그 콘텐츠가 Google 정책 기준에 부합하지 않는다고 판단되면 해당 블로그를 더 이상 일반에게 공개하지 않습니다. Google에서 실수했다고 생각되는 경우 https://www.blogger.com/unlock-blog.g?lockedBlogID=4970730075099011433에서 검토를 요청하시면 다시 확인하겠습니다. 감사합니다. Blogger팀

"

2024. 1월 18일 오전 10:29
"
안녕하세요, Blogger 커뮤니티 가이드(https://blogger.com/go/contentpolicy)에 따라, 게시하신 블로그에 대한 재검토를 실시했습니다. 검토 결과에 따라 해당 블로그는 다시 복구되었으며 http://bitsyrup.blogspot.com/에서 블로그에 액세스할 수 있습니다. 양해해 주셔서 감사합니다. 안녕히 계세요. Blogger팀

"


2023/11/28

PostgreSQL dblink 기본 사용법

PostgreSQL 에서 처음 dblink 를 사용하는 경우에는 dblink 라이브러리를 확장모듈에 로딩을 해놔야 함.  안그러면 알수 없는 함수라는 오류가 표시됨.


-- dblink 로딩 (최초1회 > PgAdmin 에서 해당 DB의 확장모듈에 표시됨)
create extension dblink;


-- DB 연결
select dblink_connect('Test연결1', 'hostaddr=127.0.0.1 port=5432 dbname=test user=test1 password=pwd1');


-- 쿼리
SELECT * FROM 
    dblink('Test연결1', 
   'SELECT "Seq" FROM dbo."Table1" WHERE "CreateDate" < now() - INTERVAL ''2 year''') as t1("Seq" integer) ;


-- DB 연결 해제
select dblink_disconnect('Test연결1');



dblink 의 단점일수도 있고 장점일수도 있긴한데,. 가져올려는 테이블 컬럼을 명시적으로 지정해줘야 하고, row를 임시 저장하는 개체(테이블)에도 명시적을 컬럼 타입을 지정해줘야 함.

컬럼 갯수가 몇개 안되면 상관없는데, 컬럼이 많으면 이것 또한 상당한 노가다 작업이 필요해 진다. 그래서 차라리 각기 호출하여 웹/백엔드 코드단에서 처리하는게 더 편할수도 있음..

그런점에서 본다면,. 확실히 Microsoft SQL Server 가 편하긴 함.




2023/07/26

PostgreSQL 백업 및 복원 예 (일반적인 논리 백업)

■ 백업

명령행 실행시 패스워드 없이 할려면, pgpass.conf 에 작업 계정에 대한 인증 설정이 미리 되어 있어야 함.


(원격)

pg_dump --host localhost --port 5432 --username "postgres" --password "" --dbname "test" --format custom --blobs --verbose --file "test.backup"


(로컬)

pg_dump --username "postgres" --no-password --dbname "test" --blobs --verbose --format=c --file "test.backup"



■ 복원

유의) 복원 대상에 세션이 물려 있는 경우에는, 복원시 대상 개체의 drop, create 쿼리 실행 오류가 발생하고, 그걸 무시하고 계속 진행하는 경우 기존 테이블에 데이터가 중복 복원 추가됨. 그러므로, 세션이 일체 물려 있지 않은 상태에서 복원 작업을 진행해야 함.

SELECT pg_terminate_backend(pid) FROM pg_stat_activity  WHERE pid <> pg_backend_pid() AND datname = 'test';


(DB 복원으로 할 경우. 대상 이름이 다른 경우 미리 생성후)

pg_restore --clean --create --no-privileges --no-owner --username "postgres" --dbname "test_new" --disable-triggers --format=c --verbose "test.backup"

--clean --create 파라미터를 주는 경우 백업에 있는 DB명으로 동일 복원. 하지만 복원 대상과 동일 DB 명을 주면 에러를 뿌림. 

pg_restore 내부 로직이 문제인지 모르겠으나,.

test 를 삭제후 test 에 복원하려면, 다른 DB명으로 복원 지정(생성)후 하면, 원래 test 를 삭제/복원. 동일하게 test 를 지정하면 DB drop,create 오류나고, 생성 안해두면 DB 없다고 또 복원 안됨..;;


(다른 DB에 단순 복원으로 할 경우. 대상 이름이 다른 경우 미리 생성후)

pg_restore --no-privileges --no-owner --username "postgres" --dbname "test_new" --format=c --verbose "test.backup"

테이블의 경우 개체가 이미 있는 경우, 거기에 레코드 추가 insert 방식이므로, 데이터 중복 발생 유의.


(대상 DB에, 대상 테이블 복원으로 할 경우)

pg_restore --clean --no-privileges --no-owner --username "postgres" --dbname "test_new" --table "table1" --disable-triggers --format=c --verbose "test.backup"

--clean 파라미터 주면, 대상 개체를 먼저 삭제후 복원. 파라미터 없는 상태에서 중복 이름 있는 경우, 데이터 중복 복원해 버리므로 유의 필요.






2023/03/16

Gmail 550-5.7.1 missing a valid messageId header 오류

Gmail 주소에 메일 전송시, 아래와 같은 리턴이 있다면, 전송 메일 주소의 SPF 설정/작동 점검을 일단 해볼 필요가 있음. 여러 가능성중에 하나.


Reporting-MTA: dns; googlemail.com
Received-From-MTA: dns; support@my-domain-com.co.kr
Arrival-Date: Wed, 15 Mar 2023 21:16:53 -0700 (PDT)
X-Original-Message-ID: <64129835.170a0220.36737.5aebSMTPIN_ADDED_MISSING@mx.google.com>

Final-Recipient: rfc822; rev-mail@gmail.com
Action: failed
Status: 5.7.1
Diagnostic-Code: smtp; 550-5.7.1 [209.85.220.69] Messages missing a valid messageId header are not
550 5.7.1 accepted. nu11-20020a17090b1b0b00b0023d2e220d6fsor1541472pjb.6 - gsmtp

Last-Attempt-Date: Wed, 15 Mar 2023 21:16:57 -0700 (PDT)


SMTP 서버에서 HeloDomain,SMTPServerDomain 에 지정한 도메인의 SPF 설정. 즉  domain.com 이면 domain.com  호스트의 SPF, mail.domain.com 이면 mail.domain.com 호스트에 SPF 설정/조회가 되도록 설정.

그외 다른 이유는..?







2023/03/01

IIS SMTP STARTTLS 전송 오류

 다음 이유 때문에 원격 도메인  'outlook.com'(으)로 배달하는 동안 '52.96.111.82' 호스트로 메시지를 배달하지 못했습니다. An SMTP protocol error occurred. 오류를 일으킨 SMTP 동사는 'MAIL'입니다.  

원격 서버의 응답은 '451 5.7.3 STARTTLS is required to send mail [BL1P221CA0028.NAMP221.PROD.OUTLOOK.COM 2023-03-01T08:3'입니다.


> IIS SMTP 설정에서, TLS 설정 


가능하면 되고 안되면 일반 연결이 되고 이런 자동 선택적 옵션이 아닌, 무조건 강제 옵션이기 때문에, 이걸 설정하면, TLS 설정을 요구하는 outbound 원격지에선 메일이 수신되지만,. STMP Inbound 에 접근하는 SMTP Client 도 모두 SSL 관련 설정이 되어 있어야 함.



2023/02/28

DistributedCOM 10016

로그 이름:         System
원본:            Microsoft-Windows-DistributedCOM
이벤트 ID:        10016

설명:
응용 프로그램별 권한 설정에서 CLSID가
{0DC1AB8B-A52D-4BA8-BD76-E2819386FB2F}
이고 APPID가
{BDBED08B-7FB7-4EEA-AFD0-53DE534CB638}

인 COM 서버 응용 프로그램에 대한 로컬 활성화 사용 권한을 응용 프로그램 컨테이너 사용할 수 없음 SID(사용할 수 없음)에서 실행 중인 주소 LocalHost(LRPC 사용)의 사용자 abc\aaa SID(S-1-5-21-1173076938-3139918828-2747313952-500)에게 부여하지 않았습니다. 구성 요소 서비스 관리 도구를 사용하여 이 보안 권한을 수정할 수 있습니다.


대상 DCOM 구성요소는 'ActivationHints' 이고,
Lib 경로는 C:\Windows\System32\twinui.appcore.dll

HKEY_CLASSES_ROOT\AppID\{bdbed08b-7fb7-4eea-afd0-53de534cb638}
LaunchPermission, RunAs=Interactive User


터미널 로그온세션과 별개로 0 세션에서 배치파일을 실행할려고 vbscript 'CreateObject("WScript.Shell").Run' 개체를 활용했는데, 이게 Windows Server 2022 부터? 터미널 로그온 상태에서, 동일 계정 다른 세션에서 실행되면, 그런것으로 보이긴 함.. (위 구성요소는 권한 설정이 잠겨 있음). 

아뭏튼, 터미널 로그온이 없는 다른 계정으로 실행하던가 하면 되긴 한데, 일단은 SYSTEM 계정으로 실행하는것으로 변경해 놓음.

그런데, ActivationHints 구성요소가 구체적으로 어떤 작동을 하는것인지, 아무리 검색해봐도 설명을 찾을수가 없넹..;;




Visual Studio CS0518 에러 메시지 표시 관련

Visual Studio 2019 에서, 이전 버전에서 작업했던 ASP.NET MVC 프로젝트를 로드하면, cshtml 에서 c# 언어쪽 문자열에서 CS0518 개체 타입 관련 경고(오류) 표시가 쭈욱 나는 증상..

빈 새프로젝트를 생성해서 비교해 보니, 이건 또 경고창이 안뜬다. web.config 에서 compilers 항목의 버전 지정값이 다르긴 한데..

그래서, 다시 기존 프로젝트를 열었던 VS 를 종료후 다시 실행하니깐.. 응??? 이건 왜 또 경고창이 발생안해 ???.....;;  cshtml 파일 razor 타입 코딩된 페이지 열면 경고창이 떳는데, 메쏘드 부분만 잘라내기 후 다시 그자리에 붙이기 하니, 경고창이 없어진다.. ㅎㅎ 

이건 아무래도.. Visual Studio 소스 편집기 "버그" 인것 같음.. 이유는 위와 같이 어떨땐 경고표시되고 어떨땐 또 정상으로 잘 확인되고... 패턴을 모르겠음..

다른 문서를 찾아보면, mscorlib.dll 로딩 문제라고 하는데 그게 맞는건지도 모르겟고.. 원인 찾아볼려고 했는데... 다들 이런 저런 얘기가 있긴 한데,. 조금씩 다른 얘기들이라서 맞는건지도 모르겠고.. 그냥 이쯤에서 종료..;;





2022/10/12

계속 하락하는 Windows Server 점유율

아래 자료는 netcraft 의 2022/10 기준 웹서버 데이터 이다. 이게 꼭 맞는건 아니지만, 대체적인 흐름을 볼수는 있다.




















(출처: Netcraft)


SW 불법복제가 횡횡하던 시절에는, Windows Server 도 제법 높은 점유율이었다. 맘대로 복사해서 그냥 아무렇지 않게 쓸수가 있었기 때문. 그러나 그 이후 저작권이 강화되면서, 수요가 점차 줄어들기 시작..

Windows Server 가 점유율이 줄어드는 가장 큰 이유는,. 시작은 10~15년전 부터 이슈가 되었던 라이센스 비용 때문이고, 그래서 신규 구축시 Linux로 마이그레이션 전환 분위기가 조금씩 있긴 했는데,. 

안드로이드등 오픈소스 쪽이 왕성해지면서, 서버쪽 어플리케이션도 하나 둘씩 Linux 기반으로 마이그레이션이 증가하고, 그런게 일반화 되다 보니,. 그래서 그쪽에 시장과 인력풀이 커지고, 그래서 굳이 꼭 Windows 이어야 할 이유도 없어지고, 그래서 수요가 점점 줄게 되고..

그리고, 특히 웹쪽에서는 단순 html,js 에 json Web API 패턴으로 변화되면서, 이제 더 이상  IIS,Apache 등의 특정 웹개발 타입(ASP,PHP 등등의) 의 종속은 없다도 봐도 무방할 정도이다. 이것 또한 굳이 IIS 를 선택할 이유가 없는 부분이기도 하고.,.

아마 10년뒤쯤인 2032년쯤에는, Windows Server 점유율은 5~10% 아래로 내려갈것 같기도 해보인다. 이렇게 예상하는 이유는... Microsoft 내부적으론 어떨지 모르겠으나, 밖에서 느껴지는 분위기는 Microsoft 가 Windows Server 성장에 그렇게 크게 관심이 없어 보이기 때문이다.

최근에 클라우드나 분산 컴퓨팅등에서,. 주류 기술은 모두 오픈소스에서 선도되고 있고, Microsoft 는 뒤늦게 반영하는 팔로워 인데, 그것도 대부분 그냥 생색내기로 보여지는 서비스 수준이다. Windows 를 통해서 그런 기술을 굳이 운영할 이유가? 없다는..

물론 현재의 Microsoft 는 애저를 통해서 엄청난 매출과 수익을 내고 있긴 하다. 그러나.. 이제 Windows Server 는 서버 시장에서, 그냥 곁가지 수준의 신세가 되가고 있다는 점.



Windows 8 / 2012 R2 TLS 1.2 Cipher suite (SSL/TLS 보안 채널 오류)

Windows 8 및 Windows Server 2012 R2 에서는,  아래와 같은 암호화 알고리즘을 지원하지 않는다. 지원은 Windows 10 및 Windows 2016 에서 부터이다.


https://learn.microsoft.com/en-us/windows/win32/secauthn/tls-cipher-suites-in-windows-8-1


# TLS 1.2 (suites in server-preferred order)

TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)   ECDH x25519

TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)   ECDH x25519



일부 서버에서, TLS 보안 강화 목적으로, SSL 은 물론이고, TLS 1.2 1.3 에서 'WEAK' 알고리즘을 제거하는 경우가 종종 있다.

그런 웹서버(웹사이트)에 접속하는 경우, "요청이 중단되었습니다. SSL/TLS 보안 채널을 만들 수 없습니다." 라는 오류를 만날수 있다.  특히.. Windows 자체 라이브러리를 활용하는 Client의 경우..

Proxy 를 이용한다고 해도, IP/MAC 등 필수 변환 정보외 나머지 패킷을 원본 서버것 그대로 전달하기 때문에, 동일하게 오류가 발생한다.

물론 크롬등과 같이 자체적으로 모듈을 가지고 있는 경우에는, OS 와 상관없이 자체적으로 처리하므로 상관이 없을수 있다.

해결책은 뭐.. 자체 알고리즘을 가지고 자체 작동하는 라이브러리를 참조하거나,... 아니면.. OS 를 업그레이드 하던가....

해외 일부 커뮤니티에는... 레지스트리를 바꿔봐라 뭐 이런 내용이 있는데, OS 자체에서 라이브러리가 없는데, 레지스트리에 글자 추가해봐야 뭔소용...


Windows Server 2016 까지는, TLS 1.2 까지만 지원되며, TLS 1.3 은 Windows Server 2019 부터 지원된다. TLS 1.3이 필요하거나, 또는 어느 시점에 되면 하위 버전은 웹브라우저(크롬등등)에서 제외 될텐데, 그때가 되면, 또 어쩔수 없이 상위 OS 버전으로 업그레이드를 해야 한다.

TLS 1.3에서 활용되는 TLS_CHACHA20_POLY1305_SHA256 알고리즘은, Windows Server 2022 에서 부터 지원된다.



----- Windows Server 2012R2 에서 지원되는 알고리즘 목록 -----

TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
TLS_RSA_WITH_AES_256_GCM_SHA384
TLS_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P384
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P384
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P384
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P256
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P384
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P384
TLS_RSA_WITH_AES_256_CBC_SHA256
TLS_RSA_WITH_AES_128_CBC_SHA256
TLS_RSA_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P384
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P256
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384_P384
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P256
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA_P256
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA_P384
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA_P256
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA_P384
TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
TLS_DHE_DSS_WITH_AES_256_CBC_SHA
TLS_DHE_DSS_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_3DES_EDE_CBC_SHA
TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA
TLS_RSA_WITH_RC4_128_SHA
TLS_RSA_WITH_RC4_128_MD5
TLS_RSA_WITH_NULL_SHA256
TLS_RSA_WITH_NULL_SHA
SSL_CK_RC4_128_WITH_MD5
SSL_CK_DES_192_EDE3_CBC_WITH_MD5







2022/02/17

클라우드플레어 2021년 4분기 DDoS 트렌드 보고서

서버 호스팅 업계등에서는 오래전 부터 익히 알려진 내용이긴 함..


- DDoS 공격의 상위 10가지 공격 벡터

- 대상 고객 설문조사에서 발견한 놀라운 결과

- 4분기에 가장 큰 타격을 입은 산업


https://content.cloudflare.com/NzEzLVhTQy05MTgAAAGCo_YB5btHehUeFPakLm2OO15MkixKQBzVxoS_BTauZ_VL7rqDN9KYqRx4d-ut_VgS9NO5W4M=




2021/11/02

c# netstat 예제

netstat.exe 에서 확인하던 정보를 C# 으로..  


        public void NetStat()
        {
            IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
            TcpConnectionInformation[] tcpConnInfoArray = ipProperties.GetActiveTcpConnections();

            foreach (TcpConnectionInformation tcpConnInfo in tcpConnInfoArray)
            {
                //TcpState tcpState = tcpConnInfo.State;
                //IPEndPoint localEndPoint = tcpConnInfo.LocalEndPoint;
                //IPEndPoint remotrEndPoint = tcpConnInfo.RemoteEndPoint;
            }
        }



더 세부적으로 깊게 접근하고 싶다면, Win32 라이브러리를 참조..;;

[DllImport("iphlpapi.dll",SetLastError=true)] 






2021/02/20

Failed to add reference to '???'. Please make sure that it is in the Global Assembly Cache. 오류

심각도 코드 설명 프로젝트 파일 비표시 오류(Suppression) 상태

오류 Failed to add reference to 'System.Linq'. Please make sure that it is in the Global Assembly Cache. 0


> 기본 참조 라이브러리 목록에 없기 때문에, 직접 해당 dll 파일 위치를 찾아서 지정...? 이게 진정 해결책? C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Linq\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Linq.dll   이렇게 직접 지정 ???

Nuget 패키지 시스템 버그 인가..?


That's a very confusing error message since the GAC isn't used to resolve references at compile time. Visual Studio should be looking under C:\Program Files(x86)\Reference Assemblies but that location shouldn't be referred to as the Global Assembly Cache.  이런것?


C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\Facades 에는 System.Linq.dll 이 있는데 여기 폴더는 참조 안함.?




 



'GetPathsOfAllDirectoriesAbove() 식을 계산할 수 없습니다' 오류

기존 Webapp 에 컴파일 버전이 2.x 인데, Nuget 에서 3.8 로 업그레이드 실행. 그런데 오류나 가서 완료되지 않았고,..  다른 MS 기본 라이브러리 업데이트도 안됨..  다시 VS 실행하니 참조 라이브러리 모두 오류..


◯◯◯◯.csproj : error  : ""◯◯◯◯.cs".GetPathsOfAllDirectoriesAbove()" 식을 계산할 수 없습니다. 'System.String.GetPathsOfAllDirectoriesAbove' 메서드를 찾을 수 없습니다. ◯◯◯◯\packages\Microsoft.Net.Compilers.3.8.0\tools\Microsoft.Managed.Core.targets


일단, VS ◯◯◯◯.csproj 프로젝트 설정 파일에서, Microsoft.Net.Compilers.3.8.0 항목을 수동 제거하고, 프로젝트 다시 로딩... 일단 경고 에러는 안뜸...

  <Import Project="..\packages\Microsoft.Net.Compilers.2.10.0\build\Microsoft.Net.Compilers.props" Condition="Exists('..\packages\Microsoft.Net.Compilers.2.10.0\build\Microsoft.Net.Compilers.props')" />

  <Import Project="..\packages\Microsoft.Net.Compilers.2.3.2\build\Microsoft.Net.Compilers.props" Condition="Exists('..\packages\Microsoft.Net.Compilers.2.3.2\build\Microsoft.Net.Compilers.props')" />


   <ErrorText>이 프로젝트는 이 컴퓨터에 없는 NuGet 패키지를 참조합니다. 해당 패키지를 다운로드하려면 NuGet 패키지 복원을 사용하십시오. 자세한 내용은 http://go.microsoft.com/fwlink/?LinkID=322105를 참조하십시오. 누락된 파일은 {0}입니다.</ErrorText>

    </PropertyGroup>

    <Error Condition="!Exists('..\packages\Microsoft.Net.Compilers.2.3.2\build\Microsoft.Net.Compilers.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Net.Compilers.2.3.2\build\Microsoft.Net.Compilers.props'))" />

    <Error Condition="!Exists('..\packages\Microsoft.Net.Compilers.2.10.0\build\Microsoft.Net.Compilers.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Net.Compilers.2.10.0\build\Microsoft.Net.Compilers.props'))" />

  </Target>


닷넷 4.6.1 프로젝트에서는 컴파일 3.8 버전이 지원안되나..? (종속성에는 버전 제한이 없음)  오류 대상 .cs 파일에 위 에러 구문 연관 클래스를 사용한게 없는데.... 어떤글에선 VS.NET 2019 버전에서만 3.x 지원된다고.. (현재 VS2015, 닷넷 4.6.1 기반)

https://www.nuget.org/packages/Microsoft.Net.Compilers/2.10.0  내용을 보면, 닷넷 4.6.1 에서는 최대 2.1 버전 까지 이고, 3.x 버전은 4.7.2+ 필요하다고 되어 있음.. > Nuget 패키지 관리자에서는 왜 업데이트 하라고 띄운것이며, 종속성 검사는 왜 안한건지...?


■ OS 에 설치된 닷넷 파일 버전은 4.8 까지 표시가되고 있으나, VS.NET 에는 4.6.1 까지만 나옴.. 별도 지원 파일을 설치하면 가능 : https://dotnet.microsoft.com/download/visual-studio-sdks?utm_source=getdotnetsdk&utm_medium=referral  에서 4.8 개발자팩 다운로드 설치.


어쨌든... 닷넷 4.x 에서는 컴파일러 3.8 버전은 설치 안되는듯.. 닷넷 5 부터 되는듯.. 정말.?  아무튼 컴파일러 버전 업데이트 포기.. 



2020/07/30

HttpClient 에서 비동기 호출시 System.Threading.Tasks.Task 오류

client.PostAsync().Result;

하나 이상의 오류가 발생했습니다., 위치: System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification) 이

요청을 보내는 동안 오류가 발생했습니다.

[SocketException (0x2746): 현재 연결은 원격 호스트에 의해 강제로 끊겼습니다]
[IOException: 전송 연결 현재 연결은 원격 호스트에 의해 강제로 끊겼습니다에서 데이터를 읽을 수 없습니다.]
[WebException: 기본 연결이 닫혔습니다. 보내기에서 예기치 않은 오류가 발생했습니다.]



여러가지 원인중 하나 >

System.Net.ServicePointManager.SecurityProtocol
System.Net.ServicePointManager.ServerCertificateValidationCallback

구성이 되어 있지 않은 경우에 발생할 수 있음.
예를 들면, 서버에서 TLS 1.2 만 허용하는데 클라이언트에서 SSL 3.0 으로 접속할때.



2020/03/12

C# Win32 API 이용해서 GUI 핸들 확인하기


키움증권 API 이용해서 직접 개발한 닷넷 기반 주식 자동 매매 GUI 프로그램의, 동작 모니터링과 자동 제어가 필요해서 위해서 참조했던 코드.

실행된 GUI 프로그램에서,  특정 핸들 개체(예를 들면 버튼)가 존재하는지 확인 후, 해당 개체에 바인딩된 Property 값을 가져오거나 클릭/글자입력 같은 Action 을 주기 위해서 활용.

Process _trader = Process.GetProcessesByName("Trader").Single();
IntPtr _handle = _trader.MainWindowHandle;
IntPtr _apiConnet1 = Win32WindowApi.FindWindowEx(_handle, IntPtr.Zero, "WindowsForms10.STATIC.app.0.34f5582_r32_ad1", "OpenAPI");

GUI 컨트롤이 계층 구조인 경우 단계적으로 찾아 가면서 접근하거나, 해당 프로세스 핸들에 속한 모든 하위 핸들을 리스트로 뽑거나 검색하여 해당 컨트롤에 대해서 제어

foreach (IntPtr _child in Win32WindowApi.GetChildWindows(pHandle))
{
    HandleRef _ref = new HandleRef(this, _child);
    int capacity = Win32WindowApi.GetWindowTextLength(_ref) * 2;

    if (capacity > 0)
    {
        StringBuilder stringBuilder = new StringBuilder(capacity);
        Win32WindowApi.GetWindowText(_ref, stringBuilder, capacity);
        Console.WriteLine(">" + stringBuilder);
    }
}

특정 컨트롤(핸들)를 찾기 위해서는, MS Spy++ 같은 유틸을 이용해서 핸들 검색시 고유한 값으로 사용할만한 부분을 미리 찾아 놓으면 됨



    class Win32WindowApi
    {
        public const int WM_COMMAND = 0x0111;
        public const int WM_LBUTTONDOWN = 0x0201;
        public const int WM_LBUTTONUP = 0x0202;
        public const int WM_LBUTTONDBLCLK = 0x0203;
        public const int WM_RBUTTONDBLCLK = 0x0206;
        public const uint WM_SETTEXT = 0x000C;  // 글자 설정
        public const int WM_CHAR = 0x0102;    // 타이핑
        public const int WM_SETFOCUS = 0x0007;
        public const int BM_CLICK = 0x00F5;
        public const int BN_CLICKED = 0;
        public const int MK_LBUTTON = 1;
 
        // Public Const WS_MINIMIZE = &H20000000
        // Public Const WS_MAXIMIZE = &H1000000
 
        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int left;
            public int top;
            public int right;
            public int bottom;
        }
 
        public delegate bool Win32Callback(IntPtr hwnd, IntPtr lParam);
 
        [DllImport("User32.dll")]
        public static extern Int32 FindWindow(String lpClassName, String lpWindowName);
 
        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
 
        [DllImport("user32.Dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool EnumChildWindows(IntPtr parentHandle, Win32Callback callback, IntPtr lParam);
 
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr GetClassName(IntPtr hWnd, System.Text.StringBuilder lpClassName, int nMaxCount);
 
        [DllImport("user32.dll")]
        public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, IntPtr lParam);
 
        [DllImport("user32.dll")]
        public static extern bool PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
 
        [DllImport("user32.dll")]
        public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
 
        [DllImport("user32.dll")]
        public static extern bool SetForegroundWindow(IntPtr hWnd);
 
        [DllImport("user32.dll")]
        public static extern IntPtr GetWindowDC(IntPtr hWnd);
 
        [DllImport("user32.dll")]
        public static extern IntPtr GetWindowRect(IntPtr hWnd, ref RECT rect);
 
        private static bool EnumWindow(IntPtr handle, IntPtr pointer)
        {
            GCHandle gch = GCHandle.FromIntPtr(pointer);
            List<IntPtr> list = gch.Target as List<IntPtr>;
            if (list == null)
                throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
            list.Add(handle);
            return true;
        }
 
        public static List<IntPtr> GetChildWindows(IntPtr parent)
        {
            List<IntPtr> result = new List<IntPtr>();
            GCHandle listHandle = GCHandle.Alloc(result);
            try
            {
                Win32Callback childProc = new Win32Callback(EnumWindow);
                EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
            }
            finally
            {
                if (listHandle.IsAllocated)
                    listHandle.Free();
            }
            return result;
        }
 
        public static string GetWinClass(IntPtr hwnd)
        {
            if (hwnd == IntPtr.Zero)
                return null;
            StringBuilder classname = new StringBuilder(100);
            IntPtr result = GetClassName(hwnd, classname, classname.Capacity);
            if (result != IntPtr.Zero)
                return classname.ToString();
            return null;
        }
 
        public static IEnumerable<IntPtr> EnumAllWindows(IntPtr hwnd, string childClassName)
        {
            List<IntPtr> children = GetChildWindows(hwnd);
            if (children == null)
            {
                yield break;
            }
 
            foreach (IntPtr child in children)
            {
                string _clsName = GetWinClass(child);
                //Console.WriteLine("find. {0:X}", _clsName);
 
                if (_clsName == childClassName)
                {
                    yield return child;
                }
                foreach (var childchild in EnumAllWindows(child, childClassName))
                {
                    //yield return childchild;
                }
            }
        }
    }


2020/03/11

2020년 03월 MS 취약점 패치 주요 사항

서버쪽에서 유의해야 하는 패치는 아래 정도이고, 그외는 별 의미 없음

CVE-2020-0645 | Microsoft IIS Server 변조 취약성
https://portal.msrc.microsoft.com/ko-KR/security-guidance/advisory/CVE-2020-0645




가장 많이 본 글