2012-03-03 81 views
3

我正在使用idTCPServer處理數據。 對於一個新設備,我需要移交給一個dll的套接字(停止tcp服務器從該套接字讀取)。TCP服務器:移交套接字連接

Indy或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的緩存數據。爲了避免這種情況,你就必須確保事件僅通過運行事件中自己的閱讀循環觸發一次,避免調用任何Indy的閱讀方法,如:

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; 

如果可能的話,一個更好的解決辦法是改變你的邏輯,不需要直接訪問套接字了。讓印地做所有的讀數正常,然後通過任何接收到的數據的處理代碼的其餘部分,例如:

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

雷米,我更新了我的問題。我有時會丟失數據.... – 2012-03-04 11:22:24

+0

感謝您的更新。也許我的問題不夠清楚,但對於1種類型的設備,DLL正在處理套接字。在這種情況下,我希望indy停止閱讀套接字(某種'雙手'或'交給dll')。該DLL是第三方庫需要一個插座。將我的測試代碼移動到一個單獨的線程中,並在OnExecute中創建一個無限循環,以便讀取所有消息。或者AContext.Binding.Reset(false);不知道這是否是正確的方法。 – 2012-03-04 19:38:59