2012-03-03 4 views
3

데이터 처리를 위해 idTCPServer를 사용하고 있습니다. 새 장치의 경우 ()을 소켓에 dll (이 소켓에서 읽기 위해 tcp 서버를 중지)로 넘겨 줘야합니다.TCP 서버 : 핸드 오버 소켓 연결

인디 또는 ICS에서 가능합니까?

[편집] 하드웨어가 부족하기 때문에 테스트 목적으로 DLL 대신 스레드를 만들었습니다.

procedure TfrmIndyMain.IdTCPServer1Connect(AContext: TIdContext); 
    begin 
    FMyThread := TMyThread.Create(true); 
    FMyThread.FSocket := AContext.Binding.Handle; 
    FMyThread.Resume; 
    end; 

    procedure TfrmTest.IdTCPServer1Execute(AContext: TIdContext); 
    begin 
    // Its necessary that indy stop reading from the socket, without reset a lot of messages is lost 
    AContext.Binding.Reset(false); //not sure if this is correct 
    end; 

    procedure TMyThread.Execute; 
    var 
    len: integer; 
    data: string; 
    begin 
    ioctlsocket(FSocket, FIONREAD, len); 
    if len>0 then 
    begin 
     Setlength(data, len); 
     if recv(FSocket, pointer(data)^, len, 0) <> SOCKET_ERROR then 
     Log('Data: ' + data) 
     else 
     Log('Error'); 
    end; 
    end; 

답변

4

는 인디에서, 당신은 TIdPeerThread.Connection.Binding.Socket 특성 (인디 9 이하) 또는 TIdContext.Connection.Socket.Binding.Handle 속성을 사용할 수 있습니다 (인디 10 - TIdContext.Binding.Handle으로 바로 가기) 기본 SOCKET 핸들에 액세스 할 수 있습니다.

업데이트 : Indy는 Indy 기반 읽기 작업 중에 소켓에서 읽은 데이터의 InputBuffer을 유지 관리합니다. 여기에는 TIdTCPConnection.Connected()에 대한 호출이 포함되며 TIdTCPServerOnExecute 이벤트의 연속 트리거 사이를 호출합니다. 따라서 캐시 된 데이터에 대해서는 InputBuffer을보고 있지 않기 때문에 소켓에있는 모든 데이터를 볼 수는 없습니다.

procedure TfrmTest.IdTCPServer1Execute(AContext: TIdContext); 
var 
    ret: Integer; 
    data: AnsiString; 
    tv: timeval; 
    fd: fd_set; 
begin 
    repeat 
    FD_ZERO(@fd); 
    FD_SET(AContext.Binding.Handle, @fd); 
    tv.tv_sec := 1; 
    tv.tv_usec := 0; 
    ret := select(0, @fd, nil, nil, @tv); 
    if ret = SOCKET_ERROR then 
    begin 
     Log('Error on select()'); 
     Break; 
    end; 
    if ret = 0 then Continue; 
    ret := ioctlsocket(AContext.Binding.Handle, FIONREAD, len); 
    if ret = SOCKET_ERROR then 
    begin 
     Log('Error on ioctlsocket()'); 
     Break; 
    end; 
    if len < 1 then Break; 
    SetLength(data, len); 
    len := recv(AContext.Binding.Handle, Pointer(data)^, len, 0); 
    if len = SOCKET_ERROR then 
    begin 
     Log('Error on recv()'); 
     Break; 
    end; 
    SetLength(data, len); 
    Log('Data: ' + data); 
    until (some stop condition); 
    AContext.Connection.Disconnect; 
end; 

가능하다면, 더 나은 솔루션은 다음과 같습니다 것을 방지하기 위해, 당신은 예를 들어, 이벤트가 이벤트 만 내 자신의 독서 루프를 실행하여 한 번 트리거 있는지 확인하고 인디의 읽기 방법 중 하나를 호출하지 않도록해야 할 것입니다 더 이상 소켓에 직접 액세스 할 필요가 없도록 논리를 변경하십시오. Indy가 정상적으로 모든 읽기 작업을 수행 한 다음 수신 된 데이터를 나머지 코드 처리에 전달합니다 (예 :

procedure TfrmTest.IdTCPServer1Execute(AContext: TIdContext); 
var 
    data: TMemoryStream; 
begin 
    with AContext.Connection.IOHandler do 
    begin 
    if InputBufferIsEmpty then 
    begin 
     CheckForDataOnSource(1000); 
     CheckForDisconnect(True); 
     if InputBufferIsEmpty then Exit; 
    end; 
    end; 
    data := TMemoryStream.Create; 
    try 
    with AContext.Connection.IOHandler do 
     ReadStream(data, InputBuffer.Size, False); 
    // use data.Memory up to data.Size bytes as needed... 
    finally 
    data.Free; 
    end; 
end; 
+0

Remy, 질문을 업데이트했습니다. 때로는 데이터가 누락되었습니다 .... –

+0

업데이트 해 주셔서 감사합니다. 어쩌면 내 질문에 충분히 명확하지 않았지만 1 종류의 장치에 대해 dll은 소켓을 처리하고 있습니다. 이 경우에 나는 indy가 소켓을 읽는 것을 멈추고 싶다. (어떤 종류의 'hand off'또는 'dll에 넘기다'). dll은 소켓이 필요한 제 3 자 라이브러리입니다. 내 테스트 코드를 별도의 스레드로 이동하고 OnExecute의 무한 루프로 인해 모든 메시지를 읽습니다. 또는 AContext.Binding.Reset (false); 그게 올바른 방법인지 확실하지 않습니다. –