TCP 服务器未接收到所有正在发送的数据
TCP server not receiving all data being sent
正在尝试设置 TCP 服务器以从流中获取数据。似乎在工作,但只有在流很小的时候。一旦我开始发送大量数据,就会失败,只有 returns 一部分字符。有人可以帮我从这里出去吗?为什么我只收到一部分我发送的数据?
服务器的流程应该是,接收所有数据,存储到数据库 (RouteInboundXml()
) 并开始侦听更多传入数据。
private void ReceivePortMessages()
{
string debug = string.Empty;
try
{
Debug.Print(" >> Starting Server");
IPAddress ipAddress = Dns.GetHostEntry(Dns.GetHostName()).AddressList.FirstOrDefault(ip => ip.AddressFamily == AddressFamily.InterNetwork);
_TcpListener = new TcpListener(ipAddress, TcpPort); ;
Debug.Print(string.Format("{0}:{1}", ipAddress.ToString(), TcpPort.ToString()));
_TcpListener.Start();
Stopwatch sw = new Stopwatch();
do
{
try
{
_TcpClient = _TcpListener.AcceptTcpClient();
Debug.Print(" >> Accept connection from client");
NetworkStream networkStream = _TcpClient.GetStream();
int receivingBufferSize = (int)_TcpClient.ReceiveBufferSize;
byte[] bytesFrom = new byte[receivingBufferSize];
int Read = 0;
string dataFromClient = string.Empty;
if (!sw.IsRunning)
{
sw.Start();
}
Read = networkStream.Read(bytesFrom, 0, receivingBufferSize);
dataFromClient = System.Text.Encoding.ASCII.GetString(bytesFrom);
dataFromClient = dataFromClient.Substring(0, dataFromClient.IndexOf("[=10=]"));
if (dataFromClient != string.Empty)
{
XmlDocument xm = new XmlDocument();
debug = dataFromClient;
xm.LoadXml(string.Format("<root>{0}</root>", dataFromClient));
XmlElement root = xm.DocumentElement;
string rootName = root.FirstChild.Name;
RouteInboundXML(rootName, dataFromClient, sw);
sw.Restart();
}
}
catch (Exception ex)
{
Debug.Print("ReceivePortMessages: " + ex.ToString());
_TcpClient.Close();
_TcpListener.Stop();
ErrorLog.Write("XmlProcessing", ex.ToString() + "\r\n" + "DataFromClient: " + debug, "ReceivePortMessages()");
return;
}
} while (true);
}
catch (Exception ex)
{
Debug.Print("ReceivePortMessages: " + ex.ToString());
ErrorLog.Write("XmlProcessing", ex.ToString(), "ReceivePortMessages()");
}
}
您似乎希望收到完整的 XML 文档 - 恰好 XML 文档 - 每次您致电 Stream.Read
.这是一个非常非常危险的假设。
流是数据流 - 虽然它会被分割成数据包进行传输,但您不应期望在 Read
次调用中接收数据,因为 [=13] =]来电。
每个连接的单个文档的详细信息
如果每个流只有一个文档,您可能可以大大简化代码并使其正常工作。只需使用接受流的 XmlDocument.Load
的重载这一事实:
using (var tcpClient = tcpListener.AcceptTcpClient())
{
XmlDocument doc = new XmlDocument();
using (var stream = tcpClient.GetStream())
{
doc.Load(stream);
}
// Use doc here
}
(如果可以,我个人会开始使用 LINQ to XML,但那是另一回事。)
多个文档的详细信息
如果您想在单个 TCP 流上发送多个消息,您应该实施某种 "chunking" 协议。这样做的一个好方法是将每条消息拆分为 "header" 和 "body",其中 header 可能与 "the number of bytes in the body" 一样简单,因此您知道要阅读多少. (或者,您可以为 header 设计协议以包含其他元数据。)
读取 header 后,您从流中读取 body,直到您读取的字节数与 header 中指示的一样多,或者您到达结尾流的(通常表示错误)。这可能需要多次 Read
调用。 然后 你处于合适的位置将数据解析为 XML 文档 - 最好不要首先强加你自己的 binary/text 解码,因为并非所有 XML 是 ASCII...
您可以设计您的协议,使消息之间只有一个分隔符——但这通常更难实现,因为它混合了"reading the data"和 "understanding the data"。如果可以改用上面描述的length-prefix方案,那就简单多了。
这是我过去用过的一些代码。
适合我。
using (TcpClient client = new TcpClient(ip, port))
{
var stm = client.GetStream();
stm.Write(data, 0, data.Length); //Write some data to the stream
byte[] resp = new byte[1024];
var memStream = new MemoryStream();
var bytes = 0;
client.Client.ReceiveTimeout = 200;
do
{
try
{
bytes = stm.Read(resp, 0, resp.Length);
memStream.Write(resp, 0, bytes);
}
catch (IOException ex)
{
// if the ReceiveTimeout is reached an IOException will be raised...
// with an InnerException of type SocketException and ErrorCode 10060
var socketExept = ex.InnerException as SocketException;
if (socketExept == null || socketExept.ErrorCode != 10060)
// if it's not the "expected" exception, let's not hide the error
throw ex;
// if it is the receive timeout, then reading ended
bytes = 0;
}
} while (bytes > 0);
return memStream.ToArray();
}
正在尝试设置 TCP 服务器以从流中获取数据。似乎在工作,但只有在流很小的时候。一旦我开始发送大量数据,就会失败,只有 returns 一部分字符。有人可以帮我从这里出去吗?为什么我只收到一部分我发送的数据?
服务器的流程应该是,接收所有数据,存储到数据库 (RouteInboundXml()
) 并开始侦听更多传入数据。
private void ReceivePortMessages()
{
string debug = string.Empty;
try
{
Debug.Print(" >> Starting Server");
IPAddress ipAddress = Dns.GetHostEntry(Dns.GetHostName()).AddressList.FirstOrDefault(ip => ip.AddressFamily == AddressFamily.InterNetwork);
_TcpListener = new TcpListener(ipAddress, TcpPort); ;
Debug.Print(string.Format("{0}:{1}", ipAddress.ToString(), TcpPort.ToString()));
_TcpListener.Start();
Stopwatch sw = new Stopwatch();
do
{
try
{
_TcpClient = _TcpListener.AcceptTcpClient();
Debug.Print(" >> Accept connection from client");
NetworkStream networkStream = _TcpClient.GetStream();
int receivingBufferSize = (int)_TcpClient.ReceiveBufferSize;
byte[] bytesFrom = new byte[receivingBufferSize];
int Read = 0;
string dataFromClient = string.Empty;
if (!sw.IsRunning)
{
sw.Start();
}
Read = networkStream.Read(bytesFrom, 0, receivingBufferSize);
dataFromClient = System.Text.Encoding.ASCII.GetString(bytesFrom);
dataFromClient = dataFromClient.Substring(0, dataFromClient.IndexOf("[=10=]"));
if (dataFromClient != string.Empty)
{
XmlDocument xm = new XmlDocument();
debug = dataFromClient;
xm.LoadXml(string.Format("<root>{0}</root>", dataFromClient));
XmlElement root = xm.DocumentElement;
string rootName = root.FirstChild.Name;
RouteInboundXML(rootName, dataFromClient, sw);
sw.Restart();
}
}
catch (Exception ex)
{
Debug.Print("ReceivePortMessages: " + ex.ToString());
_TcpClient.Close();
_TcpListener.Stop();
ErrorLog.Write("XmlProcessing", ex.ToString() + "\r\n" + "DataFromClient: " + debug, "ReceivePortMessages()");
return;
}
} while (true);
}
catch (Exception ex)
{
Debug.Print("ReceivePortMessages: " + ex.ToString());
ErrorLog.Write("XmlProcessing", ex.ToString(), "ReceivePortMessages()");
}
}
您似乎希望收到完整的 XML 文档 - 恰好 XML 文档 - 每次您致电 Stream.Read
.这是一个非常非常危险的假设。
流是数据流 - 虽然它会被分割成数据包进行传输,但您不应期望在 Read
次调用中接收数据,因为 [=13] =]来电。
每个连接的单个文档的详细信息
如果每个流只有一个文档,您可能可以大大简化代码并使其正常工作。只需使用接受流的 XmlDocument.Load
的重载这一事实:
using (var tcpClient = tcpListener.AcceptTcpClient())
{
XmlDocument doc = new XmlDocument();
using (var stream = tcpClient.GetStream())
{
doc.Load(stream);
}
// Use doc here
}
(如果可以,我个人会开始使用 LINQ to XML,但那是另一回事。)
多个文档的详细信息
如果您想在单个 TCP 流上发送多个消息,您应该实施某种 "chunking" 协议。这样做的一个好方法是将每条消息拆分为 "header" 和 "body",其中 header 可能与 "the number of bytes in the body" 一样简单,因此您知道要阅读多少. (或者,您可以为 header 设计协议以包含其他元数据。)
读取 header 后,您从流中读取 body,直到您读取的字节数与 header 中指示的一样多,或者您到达结尾流的(通常表示错误)。这可能需要多次 Read
调用。 然后 你处于合适的位置将数据解析为 XML 文档 - 最好不要首先强加你自己的 binary/text 解码,因为并非所有 XML 是 ASCII...
您可以设计您的协议,使消息之间只有一个分隔符——但这通常更难实现,因为它混合了"reading the data"和 "understanding the data"。如果可以改用上面描述的length-prefix方案,那就简单多了。
这是我过去用过的一些代码。 适合我。
using (TcpClient client = new TcpClient(ip, port))
{
var stm = client.GetStream();
stm.Write(data, 0, data.Length); //Write some data to the stream
byte[] resp = new byte[1024];
var memStream = new MemoryStream();
var bytes = 0;
client.Client.ReceiveTimeout = 200;
do
{
try
{
bytes = stm.Read(resp, 0, resp.Length);
memStream.Write(resp, 0, bytes);
}
catch (IOException ex)
{
// if the ReceiveTimeout is reached an IOException will be raised...
// with an InnerException of type SocketException and ErrorCode 10060
var socketExept = ex.InnerException as SocketException;
if (socketExept == null || socketExept.ErrorCode != 10060)
// if it's not the "expected" exception, let's not hide the error
throw ex;
// if it is the receive timeout, then reading ended
bytes = 0;
}
} while (bytes > 0);
return memStream.ToArray();
}