Tcp/Ip C#请求错误/缺少数据包
我目前正在使用一种内置嵌入式Linux web服务器的测量设备,它可以通过所谓的局域网接口进行控制。如果要更改设备的设置,必须首先发送TCP/IP登录数据包,然后发送密钥代码以控制指定功能或接收数据 例如,通过使用TCP/IP数据包工具,一切正常。从192.168.0.2(PC)到端口80的192.168.0.1(设备)的带有ASCII文本的登录数据包(这些是标准密码和登录名,所以我不会混淆): 从设备成功接收并确认,如wireshark协议所示: 但与Microsoft提供的相同请求返回错误请求错误消息。有些C#不像“数据包发送方”那样发送[FIN,ACK]数据包。来自Microsoft的修改代码如下所示:Tcp/Ip C#请求错误/缺少数据包,c#,sockets,tcp,ip,C#,Sockets,Tcp,Ip,我目前正在使用一种内置嵌入式Linux web服务器的测量设备,它可以通过所谓的局域网接口进行控制。如果要更改设备的设置,必须首先发送TCP/IP登录数据包,然后发送密钥代码以控制指定功能或接收数据 例如,通过使用TCP/IP数据包工具,一切正常。从192.168.0.2(PC)到端口80的192.168.0.1(设备)的带有ASCII文本的登录数据包(这些是标准密码和登录名,所以我不会混淆): 从设备成功接收并确认,如wireshark协议所示: 但与Microsoft提供的相同请求返回错误
// 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());
}
此代码段的输出:
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>
连接到192.168.0.1:80的插座
回声测试=HTTP/1.0 408请求超时
内容类型:text/html
日期:2018年3月26日星期一格林尼治标准时间16:41:34
连接:关闭
408请求超时
408请求超时
60秒内未出现任何请求
这封信的内容
嗯,我不知道,为什么C#不发送[FIN,ACK]消息。也许有人也有过同样的经历?还是有一个简单的解释?也许我在TCP/IP套接字中缺少一个选项?如果有帮助,我还可以提供Wireshark协议文件 我猜服务器要求发送方在发送响应之前发送FIN/ACK,是吗?FIN意味着关闭(定向)流,因此如果问题真的是缺少FIN,我猜您需要在发送请求后但在侦听响应之前添加:
sender.Shutdown(SocketShutdown.Send);
应该为出站连接提供FIN
然而,另见德克对该问题的评论;这可能只是因为您没有正确地形成完整的请求,而FIN目前正在间接地使其工作
请注意,您可能还需要设置
sender.NoDelay=true代码>,尽管这应该是不相关的。GET请求不应该以\r\n\r\n
结尾吗?TCP存在已知(自1970年代以来)竞争条件。不同的供应商允许TCP以不同的方式工作,因此您可能会发现供应商软件之间的差异。问题之一是当服务器和客户端同时尝试关闭连接时。可能无法发送FIN ACK。您应该始终只打开和关闭客户端(而不是服务器)的连接。您是否注意到60秒间隔的超时?看起来服务器试图与客户端建立http连接,但客户端没有响应,因此服务器关闭了连接。@Dirk不幸的是,这并不能解决问题。
sender.Shutdown(SocketShutdown.Send);