Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
(연관된 글이 2개 있습니다.)
(시리즈 글이 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




한글이 포함된 바이트 배열을 나눈 경우 한글이 깨지지 않도록 다시 조합하는 방법

다음과 같은 질문이 있군요. ^^

TextBox에 관해 질문 드립니다.
; https://www.sysnet.pe.kr/3/0/4909

서버로부터 수신받은 데이터가 100Byte단위로 내려옵니다.
그 데이터들을 모두 수신 받은 후 TextBox에 저장하고 있는데요.
(Multiline = true 설정 해두었습니다.)

1. 수신받은 데이터에는 한글, 숫자, 기호, 영어, 특수문자 등이 모두 포함되어 있는 상황이고 100바이트 단위로 끊어지는 구간에 다른 문자가 포함되면 TextBox에 정상적으로 출력이 되지만 한글의 경우 2바이트가 기본 단위이다보니 한글이 포함되면 "?柰′피求募?" 이런식으로 깨져서 출력되는데 어떻게 해야 해결할 수 있을지 궁금합니다.

2. ...


1번 문제를 간략하게 정리/재현해 보면 다음과 같은 코드가 됩니다.

using System;
using System.Text;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            byte [] buffer = Encoding.UTF8.GetBytes("한글 테스트입니다.");

            int splitOffset = 8;

            byte[] buf1 = new byte[splitOffset];
            Array.Copy(buffer, buf1, splitOffset);

            byte[] buf2 = new byte[buffer.Length - splitOffset];
            Array.Copy(buffer, splitOffset, buf2, 0, buffer.Length - splitOffset);

            SendBuffer(buf1);
            SendBuffer(buf2);
        }

        private static void SendBuffer(byte[] buffer)
        {
            string txt1 = Encoding.UTF8.GetString(buffer);
            Console.WriteLine(txt1);

            string txt2 = Encoding.UTF8.GetString(buffer);
            Console.WriteLine(txt2);
        }
    }
}

/*
// 출력 결과
한글 ?
한글 ?
??스트입니다.
??스트입니다.
*/

왜냐하면, 8번째 위치를 기준으로 바이트 분할을 해서 클라이언트로 전송했기 때문에 디코딩 과정에서 '테' 글자가 정상적으로 조합이 되지 않아 깨진 것입니다.

어쩔 수 없습니다. 이런 경우에 한글의 시작 위치를 판별해 디코딩을 뒤로 미뤄 처리하는 방법을 사용해야 합니다. 그런데, 이 작업을 범용적으로 구현하는 것이 꽤나 귀찮은 작업일 수 있는데요. 바로 이런 코드를 닷넷 BCL에서 Decoder를 이용해 제공하고 있습니다. 따라서, 위의 코드를 다음과 같이 변경할 수 있습니다.

static void Main(string[] args)
{
    byte [] buffer = Encoding.UTF8.GetBytes("한글 테스트입니다.");

    // ...[생략]...
    Decoder utf8Decoder = Encoding.UTF8.GetDecoder();
    SendBuffer(utf8Decoder, buf1);
    SendBuffer(utf8Decoder, buf2);
}

private static void SendBuffer(Decoder utf8, byte[] buffer)
{
    int len = utf8.GetCharCount(buffer, 0, buffer.Length);

    char[] textBuf = new char[len];
    utf8.GetChars(buffer, 0, buffer.Length, textBuf, 0);

    string txt = new string(textBuf);

    Console.WriteLine(txt);
}

위의 코드에서 utf8Decoder 인스턴스는 GetChars 메서드 호출 시 하나의 char로 조합을 할 수 없는 바이트는 내부 버퍼에 보관해 둔 후 다음번 호출에 이어서 조합하는 기능을 구현합니다.

따라서 해당 바이트 배열 전체를 처리해 주는 Decoder 인스턴스를 함께 유지해주면 한글 디코딩 시 경계 문제를 해결할 수 있습니다.

(첨부 파일은 위의 예제 코드를 포함합니다.)




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

[연관 글]






[최초 등록일: ]
[최종 수정일: 7/12/2021]

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

비밀번호

댓글 작성자
 



2017-12-01 12시17분
한글이 포함된 바이트 배열을 나눈 경우 한글이 깨지지 않도록 다시 조합하는 방법(두 번째 이야기)
; http://www.sysnet.pe.kr/2/0/11381
정성태

... [16]  17  18  19  20  21  22  23  24  25  26  27  28  29  30  ...
NoWriterDateCnt.TitleFile(s)
13222정성태1/20/20233932개발 환경 구성: 657. WSL - DockerDesktop.vhdx 파일 위치를 옮기는 방법
13221정성태1/19/20234163Linux: 57. C# - 리눅스 프로세스 메모리 정보파일 다운로드1
13220정성태1/19/20234314오류 유형: 837. NETSDK1045 The current .NET SDK does not support targeting .NET ...
13219정성태1/18/20233872Windows: 220. 네트워크의 인터넷 접속 가능 여부에 대한 판단 기준
13218정성태1/17/20233795VS.NET IDE: 178. Visual Studio 17.5 (Preview 2) - 포트 터널링을 이용한 웹 응용 프로그램의 외부 접근 허용
13217정성태1/13/20234391디버깅 기술: 185. windbg - 64비트 운영체제에서 작업 관리자로 뜬 32비트 프로세스의 덤프를 sos로 디버깅하는 방법
13216정성태1/12/20234654디버깅 기술: 184. windbg - 32비트 프로세스의 메모리 덤프인 경우 !peb 명령어로 나타나지 않는 환경 변수
13215정성태1/11/20236159Linux: 56. 리눅스 - /proc/pid/stat 정보를 이용해 프로세스의 CPU 사용량 구하는 방법 [1]
13214정성태1/10/20235729.NET Framework: 2087. .NET 6부터 SourceGenerator와 통합된 System.Text.Json [1]파일 다운로드1
13213정성태1/9/20235269오류 유형: 836. docker 이미지 빌드 시 "RUN apt install ..." 명령어가 실패하는 이유
13212정성태1/8/20235028기타: 85. 단정도/배정도 부동 소수점의 정밀도(Precision)에 따른 형변환 손실
13211정성태1/6/20235112웹: 42. (https가 아닌) http 다운로드를 막는 웹 브라우저
13210정성태1/5/20234132Windows: 219. 윈도우 x64의 경우 0x00000000`7ffe0000 아래의 주소는 왜 사용하지 않을까요?
13209정성태1/4/20234032Windows: 218. 왜 윈도우에서 가상 메모리 공간은 64KB 정렬이 된 걸까요?
13208정성태1/3/20233963.NET Framework: 2086. C# - Windows 운영체제의 2MB Large 페이지 크기 할당 방법파일 다운로드1
13207정성태12/26/20224270.NET Framework: 2085. C# - gpedit.msc의 "User Rights Assignment" 특권을 코드로 설정/해제하는 방법파일 다운로드1
13206정성태12/24/20224475.NET Framework: 2084. C# - GetTokenInformation으로 사용자 SID(Security identifiers) 구하는 방법 [3]파일 다운로드1
13205정성태12/24/20224871.NET Framework: 2083. C# - C++과의 연동을 위한 구조체의 fixed 배열 필드 사용 (2)파일 다운로드1
13204정성태12/22/20224152.NET Framework: 2082. C# - (LSA_UNICODE_STRING 예제로) CustomMarshaler 사용법파일 다운로드1
13203정성태12/22/20224311.NET Framework: 2081. C# Interop 예제 - (LSA_UNICODE_STRING 예제로) 구조체를 C++에 전달하는 방법파일 다운로드1
13202정성태12/21/20224705기타: 84. 직렬화로 설명하는 Little/Big Endian파일 다운로드1
13201정성태12/20/20225330오류 유형: 835. PyCharm 사용 시 C 드라이브 용량 부족
13200정성태12/19/20224204오류 유형: 834. 이벤트 로그 - SSL Certificate Settings created by an admin process for endpoint
13199정성태12/19/20224492개발 환경 구성: 656. Internal Network 유형의 스위치로 공유한 Hyper-V의 VM과 호스트가 통신이 안 되는 경우
13198정성태12/18/20224368.NET Framework: 2080. C# - Microsoft.XmlSerializer.Generator 처리 없이 XmlSerializer 생성자를 예외 없이 사용하고 싶다면?파일 다운로드1
13197정성태12/17/20224308.NET Framework: 2079. .NET Core/5+ 환경에서 XmlSerializer 사용 시 System.IO.FileNotFoundException 예외 발생하는 경우파일 다운로드1
... [16]  17  18  19  20  21  22  23  24  25  26  27  28  29  30  ...