나초보씨에게 소켓을 다루는 일쯤은 아무것도 아니었습니다. 이래뵈도 나초보씨는 ‘네트워크’에서 A+을 받을뻔 했었습니다. 기말시험 때 늦잠만 자지 않았더라면 말이죠. 그렇긴 해도 C++로 20줄 내지는 30줄씩 되던 소스코드가 10줄 이내로 줄어든 점은 마음에 들었습니다. 제법 편한 걸.
클라이언트가 서버에 접속하는 부분까지 완성하고 나서 데이터를 전송해보기로 했습니다. 구조체를 만들어서 전송하면 되겠지.
public struct SampleRequest
{
public int x;
}
앗. 그런데 MSDN을 열심히 찾아봐도 구조체 SampleRequest를 네크워크에 덤프시키는 방법이 없습니다. 이 문제를 해결하느라 간단한 테스트용 서버/클라이언트 제작에 이틀이나 걸린 것입니다. 결론만 요약하자면, BitConvert.GetBytes(...)
함수를 사용해서 정수값을 바이트 배열로 변환하거나, BinaryWriter.Write(...)
함수로 스트림에 바이트 배열로 변환된 정수값을 직접 써넣어야 합니다. BitConvert.GetBytes(...)
함수를 사용하는 것은 번거롭기도 하고, 나중에 문자열을 변환할 때는 사실상 써먹기가 어렵다는 단점이 있습니다.
이런 중요한 사실을 알게 된 나초보씨는 BinaryWriter
로 정수값을 전송하고, BinaryReader
로 전송된 정수값을 수신 받도록 ‘이보다 간단할 순 없다’ 서버/클라이언트를 작성했습니다.
정말 구조체를 덤프시키는 방법이 안 되나요?
아뇨, 사실은 된답니다. MSDN을 보시면
<a href="http://msdn.microsoft.com/library/kor/default.asp?url=/library/KOR/vcmex/html/vcgrfMarshalingStructures.asp" title="구조체 마샬링">MarshalAsAttribute</a>
라는 것이 있습니다. 이것을 사용하면 C++에서와 유사한 구조체 프로그래밍을 할 수 있습니다. 하지만 공용언어런타임(CLR)이 해당 구조체 메모리를 관리하지 못하게 만듭니다. 더욱이BinaryReader
나BinaryWriter
를 사용했을 때보다 소스코드가 복잡해지게 됩니다.구조체,객체를 소켓으로 전송하여 보자.라는 글은 이러한 프로그래밍 방식에 대해 상세하게 설명하고 있습니다. 직접 소스코드를 비교해 보시고 판단하시기 바랍니다.
이 글의 작가(바로 접니다.)는 이런 종류의 소켓 프로그래밍에는 이골이 났습니다. 그래서 이런 것은 쉬우니까 패스!
라고 생각하는 경우가 많습니다. 혹시라도 난 이런 것을 모르겠는데 왜 설명 안 해주지?
라는 의문이 들면, 바로 덧글을 남겨주시면 되겠습니다.
저는 가장 간단하게 서버 클라이언트를 구현하려고
서버에서 접속마다 쓰레드를 하나씩 늘리는 방식을 구현하고
StreamReader, StreamWriter를 통해서 쓰기도 하고 NetworkStream을 통해서 쓰기도 하고 했더니
결국 나중에는 쓰레드 동기화가 문제가 되버리는 바람에
결국 NetworkStream을 쓰지 않고 그저 StreamReader와 StreamWriter만을 쓰고 거기에다가 Mutex까지 덧붙이는 방식으로 쓰게 되었습니다.
StreamReader와 같은 도우미는 Stream을 직접 지니게 되어 자원을 해제할 때도 지니고 있던 Stream마저도 같이 해제해버리게 되서 참 쓰기 곤란하더군요.
C# 통신 프로그래밍이 쉬우면서도 참 곤란한 부분이었습니다.
이 글을 보니 왠지 얼마전에 작업하던 내용이 생각나서 몇자 적었습니다.
C++도 마찬가지이긴 하지만, C#으로 비동기 소켓 프로그래밍하는 게 백미랍니다. 죽어나죠. -_-;;