Q&A

  • 소켓으로 1:N 통신을 하려면 어떤식으로 클라이언트들을 인식하죠?
현재 짧은 지식과 도움으로 1:1 로 소켓 연결은 되었고 값들은 둘다 잘
넘어갑니다. 문제없이 쓰고 있는데...
지금 1:N 소켓통신을 하려합니다.
1:1이야 그냥 sendtext, Receivetext 하면 다 잘 되는데  서버가 한대 있고
여러 클라이언트들이 동시에 접속해서 먼가 다른 결과치들을 원한다고 했을 때 서버는 어떤식으로 클라이언트들을 구분하죠?
예제를 보니 socket.connection[0].sendtext('aaa') 이런 식으로 보내던데
저건 지금 커넥션 배열 0 번에 ' aaa'를 보내는거죠? (맞나?)
클라이언트들이 접속한 순서에 따라 커넥션 배열을 만드는것 같았습니다.
제가 난감한 것은

클라이언트 3개 (각각 a, b, c라고 하고..) 가...

a -> c -> b 이런 순으로 서버에 접속했다고 하면

커넥션이 0 , 1, 2 이렇게 되는건가요??
그래서 a 클라이언트에 send 하려면 커넥션을 [0]으로 하고 send 하면 알아서 보내게 되는건가요?? 서버 콤포넌트에서 자동으로 그것을 처리하나요?
그렇다면... a 한테 어떤 데이터를 보내고 있는 그 동안에(완료되지 않았을 때에) c 가 데이터를 요청하면 a를 보내면서 동시에 c에게도 데이터를 보내는건가요?? 전혀 모르겠어요..  ㅡ.ㅡ
제가 말씀드린것이 다 맞다면 마지막으로 궁금한건...
a,c,b 순이라면... 그중 c 클라이언트가 접속을 종료했어요..
그럼 남은건 a, b 인데.. 커넥션이 0,1 로  다시 되는건가요.,.. 아님.. 처음 그대로 0, 2로 되는건가요?

소켓은 기본 델파이 소켓을 이용하고 있습니다.
클라이언트는 지금 1:1 로 할때와 같은 것을 써도 상관은 없을듯 한데.. 맞나요? 아님 소스를 수정해야 하는건지...

소켓으로 1:N 통신할수 있는 서버쪽 개념좀 설명해주실분...
4  COMMENTS
  • Profile
    장태원 2003.12.30 23:32
    비스무리하게 알고 계신데요.

    윗부분은 맞습니다.

    아래부분에 종료될때는 0,1,2 에서 1이 종료되면.

    0,1 로 자동으로 정렬됩니다.

    Thread 이기
  • Profile
    김병관 2003.12.30 23:47
    저기.. 그럼요... 실제 구현을 할때에...
    예를 들면 대충 처리 과정이 이렇습니다...
    클라이언트가 필요한 데이터를 미리 정해진 커맨드문자열로 서버로 날려줍니다.
    그러면 서버가 그 커맨드를 받고 필요한 데이터를 준비합니다.
    데이터가 준비되면 그 요청했던 클라이언트에게 데이터를 날려줍니다.

    이렇게 되는건데...

    동시에 여러 클라이언트가 접속되어 있는 상태에서 한 클라이언트가 특정
    커넥션 배열값을 가지고 있을 꺼 아닙니까? 그 배열값을 보낼때와 받을 때 어떻게 같도록 하죠? 중간에 클라이언트가 하나 접속을 끊게 되면 배열값이 달라질텐데 코딩상으로 같도록 해줘야 할듯한데... 질문이 넘 난해한가요?

    3개의 클라이언트가 접속되어 있습니다.
    A => connection[0]
    B => connection[1]
    C => connection[2]

    C가 배열값 2 를 가지고 있는 상태에서 서버에 커맨드를 보냅니다.
    그 다음에 서버가 데이터를 처리중입니다. 이때 클라이언트 B가 접속을 끊습니다. 그러면 배열상태가...

    A => connection[0]
    C => connection[1]

    이렇게 되겠죠? 서버가 데이터를 처리한 다음에 다시 C한테 데이터를 전송합니다.  그런데 배열값이 1이 되어 있잖아요.. 이것을 코딩상으로 어떤식으로
    처리해야 하죠??

    감이 안오네여 ㅠ.ㅠ 어디 간단한 샘플이라도... 채팅 샘플들은 많던데

    socket.handle 을 이용하는 샘플을 봤는데... handle은 어따가 쓰는건쥐...

  • Profile
    신호성 2004.01.03 18:48
    제가 사용하는 방법은 Collection객체를 만들어 사용자 목록을 관리하는 방법입니다. ClientConnect 이벤트에서 사용자 정보객체를 생성하여 소켓의 Data프로퍼티에 설정하혀 활용하는 방법이죠.
    전체적인 구성은 상당히 복잡하고 또한 모두 공개할 수는 없는 입장입니다.
    아래 내용을 참조하시어 좀더 발전된 방법으로 구상하여 활용하는 것도 좋은 방법이라 생각됩니다.


      TSocketUserItem = class(TCollectionitem)
      private
        FDpCode          : String;             // 부서코드
        FDpName          : String;             // 부서명
        FUserID          : String;             // 사용자ID
        FUserName        : String;             // 사용자명
        FPassword        : String;             // 패스워드
        FSex             : String;             // 성별
        FJuminNo         : String;             // 주민번호
        FIPAddress       : String;             // 접속자 IP주소
        FRemoteHost      : String;             // 접속자 Host 명
        FConnectTime     : TDateTime;          // 접속시간
        FSocket          : TCustomWinSocket;   // 접속자 소켓
        FBroadcastSocket : TCustomWinSocket;   // 분산서버관리자 소켓
        FRecvMsgQueue    : TMemoryQueue;       // 메세지 큐
        FReturnMsgObj    : TMsgObject;         // Packet 메세지 Object

      public
        ChatObj                  : Pointer;
        Data                     : Pointer;
        DetailUserInfo           : Pointer;

        property  DpCode          : String read FDpCode      write SetDpCode;
        property  DpName          : String read FDpName      write FDpName;
        property  UserID          : String read FUserID      write SetUserID;
        property  UserName        : String read FUserName    write FUserName;
        property  IPAddress       : String read FIPAddress;
        property  RemoteHost      : String read FRemoteHost;
        property  Sex             : String read FSex write FSex;
        property  JuminNo         : String read FJuminNo write FJuminNo;
        property  Password        : String read FPassword write FPassword;
        property  Socket          : TCustomWinSocket read FSocket write SetSocket;
        property  BroadcastSocket : TCustomWinSocket read FBroadcastSocket write SetBroadcastSocket;
        property  ConnectTime     : TDateTime read FConnectTime write FConnectTime;
        property  Queue           : TMemoryQueue read FRecvMsgQueue write FRecvMsgQueue;
        property  ReturnMsgObj    : TMsgObject read FReturnMsgObj write FReturnMsgObj;

                   :


      TSocketUserCollection = class(TCollection)
      private
        FUserConnectionList     : TSocketUserList;
        function  GetItem(index : Integer) : TSocketUserItem;
        procedure SetItem(index : Integer; value : TSocketUserItem);
      protected
      public
        constructor Create(UserConnectionList : TSocketUserList);
        function  Add : TSocketUserItem;
        property  Items[index : Integer] : TSocketUserItem read Getitem write Setitem ; default;
        property  SocketUserList : TSocketUserList read FUserConnectionList;
      end;

      TSocketUserList = class(TComponent)
      private
        FItems : TSocketUserCollection;
        procedure   Setitems(value : TSocketUserCollection);
      published
             :
      end;


    // 접속시 사용자정보 객체를 생성하여 소켓의 Data프로퍼티에 할당
    procedure TfrmMSSocketDM.ServerSocketClientConnect(Sender: TObject;
      Socket: TCustomWinSocket);
    var
      SocketUserItem : TSocketUserItem;
    begin
      try
        if Socket.Data = nil then
        begin
          // SocketUserList는 TSocketUserList의 객체임
          SocketUserItem                  := SocketUserList.Items.Add;
          SocketUserItem.Socket        := Socket;
          Socket.Data                       := SocketUserItem;
        end;
      except
        GvLogFileObj.Write(Self, '사용자객체생성 Error', lgError);
      end;
    end;


    // 접속해제시 사용자목록에서 해당사용자의 객체를 제거
    procedure TfrmMSSocketDM.ServerSocketClientDisconnect(Sender: TObject;
      Socket: TCustomWinSocket);
    var
      SocketUser : TSocketUserItem;
    begin
      if (Socket.Data <> nil) then
      begin
        SocketUser  := TSocketUserItem(Socket.Data);
        SocketUserList.Items.Delete(SocketUser.Index);
      end;
    end;



    procedure TfrmMSSocketDM.ServerSocketClientRead(Sender: TObject;
      Socket: TCustomWinSocket);
    begin
      수신된 메세지를 사용자객체의 큐(FRecvMsgQueue)에 누적시킴
      수신된 메세지가 하나의 완전한 패킷(명령)인가를 확인하여
      명령을 처리하고
        TSocketUserItem(Socket.Data).Socket 프로퍼티를 이용하여 응답 메세지 전송
      (메세지 응답이 요청자가 아닌 다른 사용자에게 메세지를 전송하는 경우 접속자목록에서 사용자 ID 로 해당 TSocketUserItem 객체를 찾아 메세지를 전송)
    end;


  • Profile
    연기훈 2003.12.31 02:09
    전에 제가 소켓 프로그램 짤땐

    전 IP를 체크해서 데이터를 보내줬었는데..

    connection[0].remoteaddress 던가...

    클라이언트 IP를 체크할 수 있습니다.