Reputation: 11
I'm currently working with a measurement device that has an embedded Linux web server build in and could be controlled with the so called CGI-Interface over LAN. If one wants to change the settings of the device, one has to send at first a TCP/IP login packet and after this a key-code to control a specified function or receive data.
By using a TCP/IP packet tool, for example Paket Sender, everything works fine. A login packet to 192.168.0.1(Device) at port 80 from 192.168.0.2(PC) with the ASCII Text (These are standard password and login name, so I don't blur this out):
GET /cgi-bin/login.cgi?username=long&password=nga HTTP/1.0 \n \n
gets successfully received and acknowledged from the devices, as shown in the wireshark protocol: Wireshark Screenshot
But the same request with the Standard C# TCP/IP Client provided by Microsoft returns a Bad Request Error Message. Somewhat C# does not send the [FIN,ACK] Packet like "Packet Sender". The modified code from Microsoft is as follows:
// Data buffer for incoming data.
byte[] bytes = new byte[1024];
// Connect to a remote device.
try
{
// Establish the remote endpoint for the socket.
// This example uses port 11000 on the local computer.
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("192.168.0.1"), 80);
// Create a TCP/IP socket.
Socket sender = new Socket(IPAddress.Parse("192.168.0.1").AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Connect the socket to the remote endpoint. Catch any errors.
try
{
sender.Connect(remoteEP);
Console.WriteLine("Socket connected to {0}",
sender.RemoteEndPoint.ToString());
// Encode the data string into a byte array.
byte[] msg = Encoding.ASCII.GetBytes("GET /cgi-bin/login.cgi?username=long&password=nga HTTP/1.0 \n \n");
// Send the data through the socket.
int bytesSent = sender.Send(msg);
// Receive the response from the remote device.
int bytesRec = sender.Receive(bytes);
Console.WriteLine("Echoed test = {0}",
Encoding.ASCII.GetString(bytes, 0, bytesRec));
// Release the socket.
sender.Shutdown(SocketShutdown.Both);
sender.Close();
}
catch (ArgumentNullException ane)
{
Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
}
catch (SocketException se)
{
Console.WriteLine("SocketException : {0}", se.ToString());
}
catch (Exception e)
{
Console.WriteLine("Unexpected exception : {0}", e.ToString());
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Output for this snippet:
Socket connected to 192.168.0.1:80
Echoed test = HTTP/1.0 408 Request Timeout
Content-type: text/html
Date: Mon, 26 Mar 2018 16:41:34 GMT
Connection: close
<HTML><HEAD><TITLE>408 Request Timeout</TITLE></HEAD>
<BODY><H1>408 Request Timeout</H1>
No request appeared within 60 seconds
</BODY></HTML>
Wireshark Screenshot of this communication.
Well, I don't know, why C# doesn't send the [FIN,ACK] message. Maybe anyone has experienced the same? Or there is an easy explanation for this? Maybe I'm missing an option in the TCP/IP Sockets? If it helps, I could also provide the Wireshark protocol files.
Upvotes: 0
Views: 487
Reputation: 1062640
I'm guessing that the server requires the sender to send the FIN/ACK before it sends the response, yes? FIN means shutting down that (directional) stream, so if the problem really is the missing FIN, I'm guessing that what you need here is after sending the request but before listening for the response, to add:
sender.Shutdown(SocketShutdown.Send);
which should FIN the outbound connection.
However, see also Dirk's comment on the question; it could simply be that you aren't correctly forming a complete request, and that the FIN is currently making it work indirectly.
Note that you might also want to set sender.NoDelay = true;
, although that should be unrelated.
Upvotes: 1