bjones8888
asked on
Writing stream data & XML data to TIdTCPClient and TIdIOHandlerStream (Delphi 2006 & Indy10)
I am trying to implement a client connection to a server (TCP). I know the server is working because there's a VB app that makes an XMLQuery and receives a response.
I need to do the same with my Delphi 2006 Architect & Indy 10 application. Assume I know VERY little in this area and you will be close to the truth.
I was told by the folks who have the XML database server that I first have to send the size of the query in network byte order, get an Ack or Nak back, then send the query itself, and then I'll get an Ack or Nak, then the actual XML response. I'm getting an AV on the first IOHandlerStream.Write. Obviously, I don't understand what I'm doing. This must be installed later today. HELP!!
Here's my code in the FormActivate event.
procedure TForm1.FormActivate(Sender : TObject);
var
s: string;
sXML: string;
iSize: longint;
iLong: longint;
pLong, pXML: PChar;
begin
with Client do
begin
Connect;
try
sXML := '<?xml version="1.0" encoding="UTF-8"?>' + #13#10 +
' <PublicSafetyEnvelope version="1.0">' + #13#10 +
' <MessageIdentification/> <From/> <To/> <Creation/>' + #13#10 +
' <PublicSafety id="">' + #13#10 +
' <Query>' + #13#10 +
' <MainNamesTable>' + #13#10 +
' <NameNumber search_type="equal_to">9</ NameNumber >' + #13#10 +
' </MainNamesTable>' + #13#10 +
' </Query>' + #13#10 +
' </PublicSafety>' + #13#10 +
' </PublicSafetyEnvelope>';
pXML := PChar(sXML);
iSize := SizeOf(pXML);
iLong := htonl(iSize);
pLong := PChar(iLong);
IOHandlerStream.Write(pLon g^);
IOHandlerStream.Write(pXML ^);
s := IOHandlerStream.ReadLn;
ShowMessage(s);
finally
Disconnect;
end;
end;
end;
I need to do the same with my Delphi 2006 Architect & Indy 10 application. Assume I know VERY little in this area and you will be close to the truth.
I was told by the folks who have the XML database server that I first have to send the size of the query in network byte order, get an Ack or Nak back, then send the query itself, and then I'll get an Ack or Nak, then the actual XML response. I'm getting an AV on the first IOHandlerStream.Write. Obviously, I don't understand what I'm doing. This must be installed later today. HELP!!
Here's my code in the FormActivate event.
procedure TForm1.FormActivate(Sender
var
s: string;
sXML: string;
iSize: longint;
iLong: longint;
pLong, pXML: PChar;
begin
with Client do
begin
Connect;
try
sXML := '<?xml version="1.0" encoding="UTF-8"?>' + #13#10 +
' <PublicSafetyEnvelope version="1.0">' + #13#10 +
' <MessageIdentification/> <From/> <To/> <Creation/>' + #13#10 +
' <PublicSafety id="">' + #13#10 +
' <Query>' + #13#10 +
' <MainNamesTable>' + #13#10 +
' <NameNumber search_type="equal_to">9</
' </MainNamesTable>' + #13#10 +
' </Query>' + #13#10 +
' </PublicSafety>' + #13#10 +
' </PublicSafetyEnvelope>';
pXML := PChar(sXML);
iSize := SizeOf(pXML);
iLong := htonl(iSize);
pLong := PChar(iLong);
IOHandlerStream.Write(pLon
IOHandlerStream.Write(pXML
s := IOHandlerStream.ReadLn;
ShowMessage(s);
finally
Disconnect;
end;
end;
end;
ASKER
Here's the solution. The problem was that the ACK characters in response to the write statements weren't being removed from the stream. For some reason those characters were causing the ShowMessage statement to display as all spaces, but the correct response was actually in the response stream.
After stripping those off the beginning of the stream, the display was correct.
After stripping those off the beginning of the stream, the display was correct.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
procedure TForm1.FormActivate(Sender
var
s: string;
sXML: string;
sStrings: TStringList;
iSize: integer;
iLong, i: integer;
begin
with Client do
begin
Connect;
try
sXML := '';
sStrings := TStringList.Create;
sStrings.Add('<?xml version="1.0" encoding="UTF-8"?>');
sStrings.Add(' <PublicSafetyEnvelope version="1.0">');
sStrings.Add(' <MessageIdentification/> <From/> <To/> <Creation/>');
sStrings.Add(' <PublicSafety id="">');
sStrings.Add(' <Query>');
sStrings.Add(' <MainNamesTable>');
sStrings.Add(' <NameNumber search_type=''equal_to''>9
sStrings.Add(' </MainNamesTable>');
sStrings.Add(' </Query>');
sStrings.Add(' </PublicSafety>');
sStrings.Add(' </PublicSafetyEnvelope>');
for i := 0 to sStrings.count - 1 do
sXML := sXML + sStrings[i];
iSize := Length(sXML);
IOHandlerStack.open;
IOHandlerStack.Write(iSize
IOHandlerStack.Write(sXML)
s := IOHandlerStack.AllData;
IOHandlerStack.Close;
finally
Disconnect;
end;
end;
iLong := Length(s);
ShowMessage('Returned ' + IntToStr(iLong) + ' bytes. Here they are:' + Chr(13) + Chr(10) + s);
end;
For what it's worth, here's the VB app code that was given to me.
'///// This is the code that runs when the button on the form is clicked.
Private Sub submitButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles submitButton.Click
Dim myQuery As XMLQuery
myQuery = New XMLQuery
myQuery.Hostname = hostnameTextBox.Text ' this holds the tcp/ip address
myQuery.Port = Long.Parse(portTextBox.Tex
' queryRichTextBox contains the same text I'm putting into sXML above
' responseRichTextBox receives the result of the query
responseRichTextBox.Text = myQuery.SubmitQuery(queryR
End Sub
'//// this is XMLQuery.vb
'-------------------------
'-- Send the 4 byte header
Dim LengthBuffer = BitConverter.GetBytes(Leng
ClientSocket.Send(LengthBu
'-- Send the data
BytesToSend = New System.Text.ASCIIEncoding(
ClientSocket.Send(BytesToS
'-- Read the ACK (\006) or NAK (\025)
Dim AckOrNak(1) As Byte
ClientSocket.Receive(AckOr
If AckOrNak(0) <> 6 And AckOrNak(0) <> 25 Then
'-- Invalid ACK/NAK received
MessageBox.Show("Invalid ACK/NAK received: " + AckOrNak(0).ToString())
Return ""
ElseIf AckOrNak(0) = 25 Then
'-- NAK received
MessageBox.Show("NAK received from XML Query Server")
Return ""
End If
'-- Read the 4 byte response length into LengthBuffer
Dim Numbytes As Int32
Numbytes = ClientSocket.Receive(Lengt
'-- Convert the Response length into the host's byte order
Dim ResponseLengthInNetworkByt
Dim ResponseLength = IPAddress.NetworkToHostOrd
'-- Receive the message
Dim ResponseBuffer(50) As Byte
Dim BytesSoFar As Int32
Dim NumBytesToRead As Int32 = Numbytes
ResponseString = ""
While NumBytesToRead > 0
Numbytes = ClientSocket.Receive(Respo
If Numbytes > 0 Then
ReDim Preserve ResponseBuffer(Numbytes - 1)
'-- Convert the byte array into an ASCII string and add it to ResponseString
ResponseString += System.Text.ASCIIEncoding.
BytesSoFar += Numbytes
End If
If ResponseLength < BytesSoFar + ResponseBuffer.Length Then
NumBytesToRead = ResponseLength - BytesSoFar
Else
NumBytesToRead = ResponseBuffer.Length
End If
End While
'-- Shutdown and Close the socket
ClientSocket.Shutdown(Sock
ClientSocket.Close()
Return ResponseString
End Function
End Class