성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
[정성태] 저렇게 조각 코드 말고, 실제로 재현이 되는 예제 프로젝트를 압...
[정성태] Modules 창(Ctrl+Shift+U)을 띄워서, 해당 Op...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>Golang, Python, C#에서의 CRC32 사용</h1> <p> polyglot 시대에 ^^ 문자열의 hash를 언어 간에 일치하는 것이 필요하곤 합니다. 이럴 때 가볍게 쓸 수 있는 방법이 바로 CRC32인데요, 우선 python은 이렇게 구현할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > import zlib text = "Hello World" hash_value = zlib.crc32(text.encode('utf-8')) print(hash_value) // 출력 결과: 1243066710 </pre> <br /> Golang의 경우 내부에서 사용할 테이블의 생성 방법을 다양하게 제공하는데요,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > const ( // IEEE is by far and away the most common CRC-32 polynomial. // Used by ethernet (IEEE 802.3), v.42, fddi, gzip, zip, png, ... IEEE = 0xedb88320 // Castagnoli's polynomial, used in iSCSI. // Has better error detection characteristics than IEEE. // https://dx.doi.org/10.1109/26.231911 Castagnoli = 0x82f63b78 // Koopman's polynomial. // Also has better error detection characteristics than IEEE. // https://dx.doi.org/10.1109/DSN.2002.1028931 Koopman = 0xeb31d82e ) </pre> <br /> 주석을 통해 짐작할 수 있겠지만, Python과 일치하려면 IEEE 방식을 사용하면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > package main import ( "fmt" "hash/crc32" ) func main() { text := "Hello World" b := []byte(text) result := crc32.Checksum(b, crc32.MakeTable(crc32.IEEE)) // 또는, // result := crc32.Checksum(b, crc32.IEEETable) // 또는, // result := crc32.ChecksumIEEE(b) fmt.Printf("IEEE: %v\n", result) result = crc32.Checksum(b, crc32.MakeTable(crc32.Castagnoli)) fmt.Printf("Castagnoli: %v\n", result) result = crc32.Checksum(b, crc32.MakeTable(crc32.Koopman)) fmt.Printf("Koopman: %v\n", result) } /* 출력 결과 IEEE: <span style='color: blue; font-weight: bold'>1243066710</span> Castagnoli: 1763551791 Koopman: 1502986882 */ </pre> <br /> 마지막으로 C#은 어떨까요? 아쉽게도 기본 BCL에는 포함돼 있지 않고 nuget을 통해 (.NET Platform Extension인) 패키지 설치를 해야 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // Install-Package System.IO.Hashing -Version 6.0.1 // Install-Package System.IO.Hashing using System.IO.Hashing; using System.Text; // Crc32 Class // <a target='tab' href='https://docs.microsoft.com/en-us/dotnet/api/system.io.hashing.crc32'>https://docs.microsoft.com/en-us/dotnet/api/system.io.hashing.crc32</a> Crc32 crc32 = new Crc32(); var bytes = Encoding.UTF8.GetBytes("Hello World"); crc32.Append(bytes); Console.WriteLine(BitConverter.ToInt32(crc32.GetCurrentHash())); // <span style='color: blue; font-weight: bold'>1243066710</span> </pre> <br /> 사실 CRC 코드가 워낙 간단해서,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // Crc32.cs private static uint Update(uint crc, ReadOnlySpan<byte> source) { for (int i = 0; i < source.Length; i++) { byte idx = (byte)crc; idx ^= source[i]; crc = s_crcLookup[idx] ^ (crc >> 8); } return crc; } </pre> <br /> 직접 각 언어별로 만들어서 사용해 됩니다. 단지 Python의 경우는 C 언어로 만들어진 zlib의 native 코드가 실행되는 것이므로 성능을 생각한다면 직접 만드는 것은 좋은 선택이 아닙니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 참고로, 한 가지 주의 사항이 있는데요, 언어마다 다른 자료형으로 인해 음수를 가질 수 있는 hash 값에 대한 후처리가 필요할 수 있습니다. 가령 "ed43aa2a-586d-46b2-b103-92e17bf00eaf"라는 문자열은 언어마다 다른 출력을 갖습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // "ed43aa2a-586d-46b2-b103-92e17bf00eaf" CRC-32 결과 Python: 2811875030 Golang: 2811875030 C#: -1483092266 </pre> <br /> 가령 Golang의 경우 int 타입을 반환하는데 이것은 64비트에 해당하므로 0x80_00_00_00 이상의 값을 음수가 아닌 양수로 표현할 수 있습니다. 반면, C#은 부호 있는 4바이트이므로 0x7f_00_00_00(2,147,483,647)를 넘으면 음수로 표현하는 것입니다.<br /> <br /> 그래서 해당 값을 언어 간에 직렬화/역직렬화 시 그에 대한 처리가 필요할 수 있습니다. 가령, Golang에서 직렬화한 "2811875030" 값을 C#에서 단순히 Int.Parse로 복원하면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // 예외 발생 // Unhandled exception. System.OverflowException: Value was either too large or too small for an Int32. int result = int.Parse("2811875030"); </pre> <br /> 예외가 발생하므로, 정확한 바이트 범위를 서로 간에 약속해야 합니다. 가령 long으로 처리할지, 아니면 4바이트 부호 있는 정수로 합의하면 되는데, 후자로 정했다면 파이썬은 이런 식으로 처리를 추가해야 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // How to get the signed integer value of a long in python? // ; <a target='tab' href='https://stackoverflow.com/questions/1375897/how-to-get-the-signed-integer-value-of-a-long-in-python'>https://stackoverflow.com/questions/1375897/how-to-get-the-signed-integer-value-of-a-long-in-python</a> import zlib import ctypes text = "ed43aa2a-586d-46b2-b103-92e17bf00eaf" hash_value = zlib.crc32(text.encode('utf-8')) <span style='color: blue; font-weight: bold'>hash_value = hash_value & 0xFFFFFFFF hash_value = ctypes.c_int32(hash_value).value</span> print(hash_value) // 출력 결과: -1483092266 </pre> <br /> 반면 Golang은 간단하게 형변환만 하면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > var result int32 result = <span style='color: blue; font-weight: bold'>int32</span>(crc32.Checksum(b, crc32.IEEETable)) </pre> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1624
(왼쪽의 숫자를 입력해야 합니다.)