Win32 API나 MFC와 마찬가지로 .NET Framework에서도 비동기 방식으로 소켓 통신을 하기 위한 방법을 제공한다. 그 방법은 MSDN 내에 비동기 서버 소켓 사용과 비동기 클라이언트 소켓 사용에 관한 아티클에 상세하게 소개 되어 있다.

이 글에서 소개하고자 하는 AsyncSocketClient와 AsyncSocketServer는 .NET Framework에서 제공하는 비동기 소켓을 좀 더 사용하기 쉽게 만든 일종의 Wrapper 라이브러리라고 할 수 있다. 물론, .NET Framework 자체에서 소켓을 좀 더 고수준화한 TcpClient와 TcpListener란 클래스도 제공하지만; 제약이 많다;

물론, Socket에서 제공하는 모든 부분까지 구현한 것은 아니고; Connect, Close, Send, Receive, Accept 정도만 제공하는 것으로 소스를 공개함으로써 누구나 수정, 재배포가 가능하도록 하였다(다시 말해서; 자기가 필요한 부분은 추가로 구현해서 써도 상관없다.); 하지만, 가급적이면 저의 흔적을 말살하지 않기를..ㅠㅠ;

아, 그리고 이 라이브러리는 100% TCP 기반으로 구현되어 있다; UDP는 제공하지 않는다;

이 라이브러리가 .NET Framework에서 제공하는 소켓 클래스보다 편리한 부분은 소켓에서 발생하는 Connect, Close, Accept, Error, Send, Receive 등을 이벤트화 하였기에; 폼이나 다른 클래스에서 소켓을 핸들링 하는 것이 쉬워졌다; 다시 말해서, 폼이나 클래스에서 이벤트 핸들러만 재정의하면 소켓 이벤트를 처리할 수 있다;

사용자 삽입 이미지

위 그림에서 알 수 있듯이, 본 라이브러리는 기본적으로 AsyncSocketClass란 하나의 부모 클래스와 클라이언트 소켓 파트를 구현한 AsyncSocketClient, 서버 소켓 파트를 구현한 AsyncSocketServer로 이루어져 있다;

자식 클래스들을 좀 더 자세히 살펴보면 다음과 같다;

사용자 삽입 이미지
AsyncSocketClient는 public method로 Connect, Close, Send, Receive가 지원된다; 하지만; Receive는 특수한 경우를 제외하고는 개발자가 직접 호출할 필요는 없다; (이 부분은 나중에 좀 더 자세하게 설명하도록 한다..) 왜냐하면; 기본적으로 연결이 성공하면 데이터 수신을 위해 자동적으로 수신 대기 상태가 되기 때문이다;

만약, 데이터 수신을 성공하면, OnReceive 이벤트를 재정의 하여, 이 이벤트 핸들러에서 수신한 데이터를 지지고 볶고 하면 된다.OnConnect, OnClose, OnSend 모두 같다;

아래는 AsyncSocketClient를 이용해 구현한 샘플 프로그램의 코드 일부(이벤트 재정의 부분)이다.
사용자 삽입 이미지

여기서 중요한 것은 AsyncSocketClient 생성자의 인자로 숫자 0이 들어갔는데; 이는 다수의 AsyncSocketClient 인스턴스들을 생성을 가졍했을 때, 각각을 식별하기 위한 ID라고 할 수 있다.

그리고 그 아래 OnConnect 이벤트 핸들러가 있는데;
인자로 object sender와 AsyncSocketConnectionEventArgs e가 들어간다.

sender는 AsyncSocketClient로 캐스팅해서 쓰면, 이벤트가 발생한 소켓 클라이언트 자신이다;
(AsyncSocketClient worker = (AsyncSocketClient)sender;)

AsyncSocketConnectionEventArgs는 이벤트가 발생한 소켓 클라이언트의 ID 등을 포함하고 있다;

사용자 삽입 이미지

OnReceive를 살펴보면 넘어오는 Event 인자가 소켓의 ID, 수신한 바이트 수(ReceivedBytes), 수신한 데이터(ReceivedData)가 포함되어 있음을 알 수 있다. 참고로 위의 코드는 수신한 데이터가 byte[] 타입이기 때문에, string으로 캐스팅하기 위한 Encoding.... 코드가 포함되어 있다.

그 다음 AsyncSocketServer로 넘어가면;

AsyncSocketServer는 public method로 Listen, Stop이 지원된다; 만약 Client의 접근이 Accept 되면, OnAccept 이벤트가 발생하므로, OnAccept 이벤트를 재정의 하여, Client를 처리하면 된다;

사용자 삽입 이미지

AsyncSocketServer에서 가장 중요한 부분은 클라이언트 소켓의 접속을 처리하는 OnAccept 부분이다.

OnAccept에서 넘어오는 Event 인자는 접속이 허가된 소켓(e.Worker) 인스턴스가 포함되어 있다;

따라서, OnAccept 이벤트 핸들러에서는 AsyncSocketClient를 그대로 이용하기 위해, 이벤트 핸들러 내의
첫 줄과 같은 코드가 필요하다; 또한; 클라이언트의 ID가 중복되지 않도록, 새로운 ID도 부여한다.

그리고 그 다음이 앞서 언급한 AsyncSocketClient가 Receive를 호출해야할 특수한 상황이다;
구현 방법에 따라서; 이 부분은 Accept 코드 내에서 처리할 수도 있었지만; 어짜피 개발자가 이벤트 핸들러 연결도 필요하기 때문에; 그냥 이렇게 구현하였다.

끝으로 새로 생성한 클라이언트 소켓들을 미리 정의한 이벤트 핸들러와 연결하는 코드들이 나오고;
끝으로 클라이언트 리스트에 Add한다. (다수의 클라이언트 접속 가능 예를 들기 위해서 이렇게 했음);

좀 더 편리한 개발을 위해서는; MSDN 수준의 Class Specification을 쓰고 싶었지만; 시간 및 기타 여건이 허락되지 않는 관계로 이만 줄임!

대신에 라이브러리 및 예제 소스를 공개하니; 이를 이용하면 되지 않을까... 무책임하게 생각해봅니다;

다운로드: http://www.nohungry.net/Data/AsyncSocket.zip
크리에이티브 커먼즈 라이센스
Creative Commons License

Trackback

Trackback Address :: http://www.nohungry.net/tt1/trackback/160

Comments

  1. 카논 2010/03/09 10:52

    좋은 정보 감사합니다.
    서버/클라에 대한 구현 팁을 좀더 알려주셧으면 하는..
    초보자에게 정말 많은 도움이 될거 같습니다.

    perm. |  mod/del. |  reply.
    • 노헝그리 2010/03/09 17:33

      저도 아는 것이 없지만; 매우 기초적인 내용으로 조금씩 쓰려고 생각 중이었습니다;

      날개발자지만; 명색이 직딩이다보니~ 잘 안되지만; 틈틈이 써보도록 하겠습니다~^^;

  2. 김용수 2010/03/31 18:34

    테스트를 해보왔는데...소켓에 대한 close가 안됩니다..ㅠㅠ
    이벤트가 발생을 안하네요

    perm. |  mod/del. |  reply.
  3. 김기범 2010/05/10 09:53

    위 코드의 경우,

    여러번 Send()를 날렸을 때

    onReceive() 이벤트가 byte[]가 중첩되어 발생하는 경우가 있는데요
    (접속상태가 좋지 못하거나, 지연되는 네트워크일때 더더욱)

    이것은 정상인 것인가요? 아니면 의도되지 않은 오류인가요?

    예) 10bytes를 빠르게 여러번 Send() ->

    onReceive() 에서 발생되는 이벤트가, 10, 10, 20, 10, 20, 30, 10 등

    중첩되어 발생되는 경우가 있음

    perm. |  mod/del. |  reply.
    • 노헝글이 2010/05/10 22:47

      제가 회사를 옮기고, 회사 보안 정책 상 회사에서 블로그나 데브피아에 글을 적을 수 없어 이제 확인합니다;

      소켓 통신에서는 10바이트를 보낸다고 항상 받는 쪽에서도 10바이트를 받는다고 보장할 수 없습니다.

      님의 말씀처럼 네트워크 지연이나 기타 원인으로 인해 당연히 중첩되어 받을 수 있습니다. 즉, 정상이라는 얘기입니다.

      따라서, 데이터를 받는 쪽은 버퍼(흔히 큐를 많이 이용합니다.)를 이용해서 데이터를 처리하고, 데이터를 보내는 쪽에서는 보낸 데이터들을 구분하기 위해 데이터에 STX, ETX와 같은 구분자를 붙여서 보내고는 합니다.

  4. 이민규 2010/05/19 11:29

    저도 Close할 때 오류가 나네요.

    perm. |  mod/del. |  reply.
  5. 이민규 2010/05/20 16:29

    Close 오류는 해결했는데,
    이제는 Close할 때 이전에 보냈던 hello가 또 보내지네요;;

    perm. |  mod/del. |  reply.

What's on your mind?

댓글 입력 폼
[로그인][오픈아이디란?]