Microsoft MVP성태의 닷넷 이야기
.NET Framework: 373. C# 문자열의 인코딩이란? [링크 복사], [링크+제목 복사],
조회: 46247
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 1개 있습니다.)
(시리즈 글이 7개 있습니다.)
.NET Framework: 248. 닷넷에서 지원되는 문자열 인코딩 이름 목록
; https://www.sysnet.pe.kr/2/0/1147

.NET Framework: 368. Encoding 타입의 대체(fallback) 메카니즘
; https://www.sysnet.pe.kr/2/0/1446

.NET Framework: 373. C# 문자열의 인코딩이란?
; https://www.sysnet.pe.kr/2/0/1461

.NET Framework: 701. 한글이 포함된 바이트 배열을 나눈 경우 한글이 깨지지 않도록 다시 조합하는 방법
; https://www.sysnet.pe.kr/2/0/11378

.NET Framework: 702. 한글이 포함된 바이트 배열을 나눈 경우 한글이 깨지지 않도록 다시 조합하는 방법(두 번째 이야기)
; https://www.sysnet.pe.kr/2/0/11381

.NET Framework: 867. C# - Encoding.Default 값을 바꿀 수 있을까요?
; https://www.sysnet.pe.kr/2/0/12037

닷넷: 2190. C# - 닷넷 코어/5+에서 달라지는 System.Text.Encoding 지원
; https://www.sysnet.pe.kr/2/0/13506




C# 문자열의 인코딩이란?

오늘 아는 분으로부터 뜻밖의 질문을 받아서... ^^ 음... 이런 것도 헷갈릴 수 있겠구나... 하는 생각이 들어 정리해 보았습니다.

일단, 그 분의 질문은 이런 것이었습니다.

Java의 Netty 서버로 전송하는데, 당연히 Java 클라이언트는 잘 실행이 되지만 C#으로 만든 클라이언트는 한글만 들어가면 호출에 실패한다.


이런 경우... 대부분 인코딩 문제인데요. 그래서, Java 클라이언트와 C# 클라이언트를 각각 실행하고 그 순간의 통신을 Network Monitor로 가로채서 한글이 있는 부분을 확인해 보라고 했습니다.

그 결과, "서울"이라는 문자열을 보낸 경우 각각 다음의 바이트 값들이 보였다고 합니다.

* Java
EC 84 9c EC 9A B8 
 
* C#
BC AD BF EF

해보시면 알겠지만, Java의 결과는 UTF-8 인코딩 된 바이트 스트림이고, C#의 결과는 ks_c_5601-1987의 것입니다. 원인 파악이 되었으니 이제 다음과 같이 코딩을 해서 넘겨주면 되는 일이었습니다.

string txt = "서울";

byte [] contents = Encoding.UTF8.GetBytes(txt);

// 이후, contents 배열을 Netty 서버에 전송

그런데, 그 분이 즐겨 사용하던 Netty용 C# 라이브러리의 전송 API가 다음과 같이 문자열을 받는 것이었다고 합니다.

public class Netty
{
    public static void Send(string txt);
}

그래서... 전송을 아래와 같은 식으로 해버린 것이지요.

===== 전에는 이렇게 했는데 =====
string txt = "서울";
Netty.Send(txt);

===== 인코딩을 위해 다음과 같이 변경 =====
string txt = "서울";

byte [] contents = Encoding.UTF8.GetBytes(txt);
string output = Encoding.UTF8.GetString(contents);

Netty.Send(output); // 다시 C# string 인스턴스를 인자로 제공

문제는, ^^ 인코딩을 한 바이트 배열을 다시 string으로 변환했다고 해서 그것이 C# string의 메모리에 UTF-8로 저장되는 것은 아니라는 점입니다. 왜냐하면, C#은 string 인스턴스의 모든 바이트 배열을 무조건 UTF-16 LE 방식으로 인코딩시켜 메모리에 들고 있기 때문입니다. 즉, 모든 Encoding.GetString 메서드는 특정 인코딩 방식으로 변환된 바이트 배열을 UTF-16 LE 인코딩으로 다시 변환시키는 역할을 합니다.

위의 코드가 문제가 되는 이유는 결국 Netty.Send 메서드 내에서 다음과 같이 전송을 하기 때문입니다.

public static void Send(string txt)
{
    byte [] encoded = Encoding.Default.GetBytes(txt); // 한글 윈도우의 경우, Default == ks_c_5601-1987
    Socket.Send(encoded);
}

이를 해결하기 위해서는 Netty 라이브러리가 인코딩 인자를 하나 더 받는 메서드를 제공해 주던가,

public static void Send(string txt, Encoding encoder)
{
    byte [] encoded = encoder.GetBytes(txt);
    Socket.Send(encoded);
}

Netty.Send("서울", Encoding.UTF8);

아니면 직접 바이트 배열을 받는 메서드가 있어야 합니다.

public static void Send(byte [] buffer)
{
    Socket.Send(buffer);
}

byte [] contents = Encoding.UTF8.GetBytes(txt);
Netty.Send(contents);

(2020-10-24 업데이트) 공식적이지는 않지만 이런 상황에서 다음의 우회 방법이 있습니다.

C# - Encoding.Default 값을 바꿀 수 있을까요?
; https://www.sysnet.pe.kr/2/0/12037




참고로, 다음의 글을 보시면 더욱 도움이 되겠지요. ^^

유니코드와 한글 - 유니코드와 닷넷을 이용한 한글 처리
; https://www.sysnet.pe.kr/2/0/1294




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 6/27/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 61  62  63  64  65  66  67  68  69  [70]  71  72  73  74  75  ...
NoWriterDateCnt.TitleFile(s)
12247정성태6/29/202020364.NET Framework: 918. C# - 불린 형 상수를 반환값으로 포함하는 3항 연산자 사용 시 단축 표현 권장(IDE0075) [2]파일 다운로드1
12246정성태6/29/202021986.NET Framework: 917. C# - USB 관련 ETW(Event Tracing for Windows)를 이용한 키보드 입력을 감지하는 방법
12245정성태6/24/202022299.NET Framework: 916. C# - Task.Yield 사용법 (2) [2]파일 다운로드1
12244정성태6/24/202022551.NET Framework: 915. ETW(Event Tracing for Windows)를 이용한 닷넷 프로그램의 내부 이벤트 활용 [1]파일 다운로드1
12243정성태6/23/202018301VS.NET IDE: 147. Visual C++ 프로젝트 - .NET Core EXE를 "Debugger Type"으로 지원하는 기능 추가
12242정성태6/23/202020218오류 유형: 623. AADSTS90072 - User account '...' from identity provider 'live.com' does not exist in tenant 'Microsoft Services'
12241정성태6/23/202022349.NET Framework: 914. C# - Task.Yield 사용법파일 다운로드1
12240정성태6/23/202023440오류 유형: 622. 소켓 바인딩 시 "System.Net.Sockets.SocketException: An attempt was made to access a socket in a way forbidden by its access permissions" 오류 발생
12239정성태6/21/202023256Linux: 30. (윈도우라면 DLL에 속하는) .so 파일이 텍스트로 구성된 사례 [1]
12238정성태6/21/202020711.NET Framework: 913. C# - SharpDX + DXGI를 이용한 윈도우 화면 캡처 라이브러리
12237정성태6/20/202020574.NET Framework: 912. 리눅스 환경의 .NET Core에서 "test".IndexOf("\0")가 0을 반환
12236정성태6/19/202021653오류 유형: 621. .NET Standard 대상으로 빌드 시 dynamic 예약어에서 컴파일 오류 - error CS0656: Missing compiler required member 'Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create'
12235정성태6/19/202019253오류 유형: 620. Windows 10 - Inaccessible boot device 블루 스크린
12234정성태6/19/202018864개발 환경 구성: 494. NuGet - nuspec의 패키지 스키마 버전(네임스페이스) 업데이트 방법
12233정성태6/19/202020429오류 유형: 619. SQL 서버 - The transaction log for database '...' is full due to 'LOG_BACKUP'. - 두 번째 이야기
12232정성태6/19/202018568오류 유형: 618. SharePoint - StoreBusyRetryLater 오류
12231정성태6/15/202022479.NET Framework: 911. Console/Service Application을 위한 SynchronizationContext - AsyncContext
12230정성태6/15/202021116오류 유형: 617. IMetaDataImport::GetMethodProps가 반환하는 IL 코드 주소(RVA) 문제
12229정성태6/13/202023246.NET Framework: 910. USB/IP PROJECT를 이용해 C#으로 USB Keyboard + Mouse 가상 장치 만들기 [1]
12228정성태6/12/202021480.NET Framework: 909. C# - Source Generator를 적용한 XmlCodeGenerator파일 다운로드1
12227정성태6/12/202025424오류 유형: 616. Visual Studio의 느린 업데이트 속도에 대한 원인 분석 [5]
12226정성태6/11/202024825개발 환경 구성: 493. OpenVPN의 네트워크 구성 [4]파일 다운로드1
12225정성태6/11/202022145개발 환경 구성: 492. 윈도우에 OpenVPN 설치 - 클라이언트 측 구성
12224정성태6/11/202031482개발 환경 구성: 491. 윈도우에 OpenVPN 설치 - 서버 측 구성 [1]
12223정성태6/9/202028862.NET Framework: 908. C# - Source Generator 소개 [10]파일 다운로드2
12222정성태6/3/202020015VS.NET IDE: 146. error information: "CryptQueryObject" (-2147024893/0x80070003)
... 61  62  63  64  65  66  67  68  69  [70]  71  72  73  74  75  ...