gpt4 book ai didi

C# 在 TCP 上读取数据并不总是读取所有数据

转载 作者:可可西里 更新时间:2023-11-01 02:50:27 24 4
gpt4 key购买 nike

这是我的 TCP 监听器,它读取接收到的数据:

    private void Update()
{
//Console.WriteLine("Call");
if (!serverStarted)
{
return;
}

foreach (ServerClient c in clients.ToList())
{
// Is the client still connected?
if (!IsConnected(c.tcp))
{
c.tcp.Close();
disconnectList.Add(c);
Console.WriteLine(c.connectionId + " has disconnected.");
CharacterLogout(c.connectionId);
continue;
//Console.WriteLine("Check for connection?\n");
}
else
{
// Check for message from Client.

NetworkStream s = c.tcp.GetStream();
if (s.DataAvailable)
{
StreamReader reader = new StreamReader(s, true);
string data = reader.ReadLine();

if (data != null)
{
OnIncomingData(c, data);
}
}
//continue;
}
}

for (int i = 0; i < disconnectList.Count - 1; i++)
{
clients.Remove(disconnectList[i]);
disconnectList.RemoveAt(i);
}


}

private bool IsConnected(TcpClient c)
{
try
{
if (c != null && c.Client != null && c.Client.Connected)
{
if (c.Client.Poll(0, SelectMode.SelectRead))
{
return !(c.Client.Receive(new byte[1], SocketFlags.Peek) == 0);
}

return true;
}
else
{
return false;
}
}
catch
{
return false;
}
}

private void StartListening()
{
server.BeginAcceptTcpClient(OnConnection, server);
}

通常这工作正常。例如,当我每 2、3 秒或更长的时间间隔发送一个请求时,一切正常。

但是,当我发送请求时,例如每 1 秒发送 2、3 个请求,甚至更短的时间,一开始它工作正常,过了一会儿它只是削减了接收到的数据。

如果我经常发送请求,我就会收到问题。这是收到的数据示例。

Character position Updated
{"header":"1x008","data":{"characterId":"1","position.x":"257.8289","position.z":"251.5683","position.y":"2.798551"},"connectionId":1}
Character position Updated
{"header":"1x008","data":{"characterId":"1","position.x":"257.8895","position.z":"251.6447","position.y":"2.796823"},"connectionId":1}
Character position Updated
{"header":"1x008","data":{"characterId":"1","position.x":"257.9507","position.z":"251.7218","position.y":"2.795079"},"connectionId":1}
Character position Updated
{"header":"1x008","data":{"characterId":"1","position.x":"258.0536","position.z":"251.8516","position.y":"2.792141"},"connectionId":1}
Character position Updated
{"header":"1x008","data":{"characterId":"1","position.x":"258.2184","position.z":"252.0594","position.y":"2.793153"},"connectionId":1}
Character position Updated
{"header":"1x008","data":{"characterId":"1","position.x":"258.2699","position.z":"252.1243","position.y":"2.795335"},"connectionId":1}
Character position Updated
{"header":"1x008","data":{"characterId":"1","position.x":"258.3738","position.z":"252.2554","position.y":"2.799742"},"connectionId":1}
Character position Updated
{"header":"1x008","data":{"characterId":"1","position.x":"258.5936","position.z":"252.5325","position.y":"2.80906"},"connectionId":1}
Character position Updated
{"header":"1x008","data":{"characterId":"1","position.x":"258.7353","position.z":"252.7112","position.y":"2.815068"},"connectionId":1}
Character position Updated
{"header":"1x008","data":{"characterId":"1","position.x":"258.7883","position.z":"252.778","position.y":"2.817239"},"connectionId":1}
Character position Updated
{"header":"1x008","data":{"characterId":"1","position.x":"258.9598","position.z":"252.9942","position.y":"2.809892"},"connectionId":1}
Character position Updated
{"header":"1x008","data":{"characterId":"1","position.x":"259.0203","position.z":"253.0705","position.y":"2.806783"},"connectionId":1}
Character position Updated
{"header":"1x008","data":{"characterId":"1","position.x":"259.0894","position.z":"253.1577","position.y":"2.803234"},"connectionId":1}
Character position Updated
{"header":"1x008","data":{"characterId":"1","position.x":"259.2439","position.z":"253.3524","position.y":"2.795195"},"connectionId":1}
Character position Updated
{"header":"1x008","data":{"characterId":"1","position.x":"259.4146","position.z":"253.5677","position.y":"2.784776"},"connectionId":1}
Character position Updated
{"header":"1x008","data":{"characterId":"1","position.x":"259.5829","position.z":"253.7799","position.y":"2.772557"},"connectionId":1}
Character position Updated
{"header":"1x008","data":{"characterId":"1","position.x":"259.7452","position.z":"253.9845","position.y":"2.762063"},"connectionId":1}
Character position Updated
{"header":"1x008","data":{"characterId":"1","position.x":"259.8754","position.z":"254.1487","position.y":"2.760789"},"connectionId":1}
Character position Updated
{"header":"1x008","data":{"characterId":"1","position.x":"260.0437","position.z":"254.3609","position.y":"2.759143"},"connectionId":1}
Character position Updated
{"header":"1x008","data":{"characterId":"1","position.x":"260.2104","position.z":"254.5711","position.y":"2.757511"},"connectionId":1}
Character position Updated
{"header":"1x008","data":{"characterId":"1","position.x":"260.5002","position.z":"254.8992","position.y":"2.756335"},"connectionId":1}
Character position Updated
{"header":"1x008","data":{"characterId":"1","position.x":"260.9822","position.z":"255.1375","position.y":"2.765062"},"connectionId":1}
Character position Updated
{"header":"1x008","data":{"characterId":"1","position.x":"261.5056","position.z":"255.2772","position.y":"2.787397"},"connectionId":1}
Character position Updated
{"header":"1x008","data":{"characterId":"1","position.x":"261.5968","position.z":"255.3015","position.y":"2.791161"},"connectionId":1}
Character position Updated
{"header":"1x008","data":{"characterId":"1","position.x":"261.7819","position.z":"255.3509","position.y":"2.797171"},"connectionId":1}
Character position Updated
{"header":"1x008","data":{"characterId":"1","position.x":"261.8941","position.z":"255.3809","position.y":"2.799694"},"connectionId":1}
Character position Updated
ion.z":"255.5631","position.y":"2.815049"},"connectionId":1}

正如您在最后一行中看到的,JSON 已损坏。数据无缘无故地减少了,它破坏了我的代码。

我可以确认客户端为在服务器/监听器端出现的最后一行发送了有效的 JSON 字符串。

我认为这可能与缓冲区大小有关,但我对这种 TCP 通信还很陌生。

这是来自客户端的发送函数:

public void Send(string header, Dictionary<string, string> data)
{

if (stream.CanRead)
{
socketReady = true;
}

if (!socketReady)
{
return;
}
JsonData SendData = new JsonData();
SendData.header = "1x" + header;
foreach (var item in data)
{
SendData.data.Add(item.Key.ToString(), item.Value.ToString());
}
SendData.connectionId = connectionId;

string json = JsonConvert.SerializeObject(SendData);
var howManyBytes = json.Length * sizeof(Char);
writer.WriteLine(json);
writer.Flush();

Debug.Log("Client World:" + json);
}

我的错误在哪里,我该如何改正?

最佳答案

StreamReader 包含两个内部缓冲区 - 一个已解码但尚未使用的字符,以及一个已接收但尚未解码的字节(对于多字节编码可能是不完整的字符) ).当它需要数据时,它首先检查缓冲区,如果没有它需要的数据,它就会从流中读取“一些”数据,直到它可以完成当前请求 (ReadLine()管他呢)。在某些消息稀疏的情况下,这可能意味着它会完整地读取一条消息,这可能会错误地表明您的代码正在运行。但是,当多条消息靠得很近时,它可能会过度读取 套接字 - 接收一条消息的全部和另一条消息的一部分。这意味着非常重要的是保留每个套接字的StreamReader - 否则当你把它掉在地上时,你会丢失所有消耗的数据从套接字但未在前面的 ReadLine() 中读取。这将完全您看到的结果。所以:作为一个简单的修复:不是存储套接字,而是存储套接字的元组及其StreamReader - 并且只为每个套接字创建一个读取器。

或者,您可以编写更好的“框架”代码并(在某处)手动缓冲数据,直到您的框架完成(在您的情况下为行尾)。然后处理后台缓冲区,注意保留帧之后留下的任何额外字节。如果您不熟悉网络代码,第一个选项可能更简单。不过,第二个选项更好 - 它避免在接收到部分帧时阻塞。目前,单个客户端可以通过发送一些没有换行的文本并保持套接字打开(可能每 30 秒输入一个额外的字符)来杀死您的服务器。这将导致您的服务器永远停止在 ReadLine() - 或者直到您的服务器 OOM,因为如果传入文本。哎呀,发送一大段没有换行的文本!


可以像(使用 C# vCurrent)一样简单

List<(Socket socket, StreamReader reader)> sockets = ...

...


// (adding)
var newSocket = ...
var reader = new StreamReader(...); // on newSocket
sockets.Add((newSocket, reader));
// ...

foreach(var pair in sockets) {
// ...
var socket = pair.socket;
var line = pair.reader.ReadLine();
if(line != null) {...}
// ...
}

关于C# 在 TCP 上读取数据并不总是读取所有数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47380819/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com