Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/302.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#在TCP上读取数据并不总是读取所有数据_C#_Json_Sockets_Tcp - Fatal编程技术网

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

C#在TCP上读取数据并不总是读取所有数据,c#,json,sockets,tcp,C#,Json,Sockets,Tcp,下面是我的TCP侦听器,它读取接收到的数据: private void Update() { //Console.WriteLine("Call"); if (!serverStarted) { return; } foreach (ServerClient c in clients.ToList()) { // Is the clie

下面是我的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);
    }
正如您在最后一行中看到的,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);
}
public void发送(字符串头、字典数据)
{
if(stream.CanRead)
{
socketReady=true;
}
如果(!socketReady)
{
返回;
}
JsonData SendData=新的JsonData();
SendData.header=“1x”+表头;
foreach(数据中的var项)
{
SendData.data.Add(item.Key.ToString(),item.Value.ToString());
}
SendData.connectionId=connectionId;
字符串json=JsonConvert.SerializeObject(SendData);
var howManyBytes=json.Length*sizeof(Char);
WriteLine(json);
writer.Flush();
Log(“客户端世界:+json”);
}

我的错误在哪里?如何修复?

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

或者,您可以编写更好的“帧”代码并手动缓冲数据(某处),直到您的帧完成(在您的示例中是行尾)。然后处理后缓冲区,小心保留帧后剩余的任何额外字节。如果您不熟悉网络代码,第一个选项可能更简单。不过,第二个选项更好——它可以避免在接收到部分帧时阻塞。目前,单个客户端可以通过发送一些文本而不使用换行符,并保持套接字打开(可能每30秒增加一个字符)来杀死服务器。这将导致您的服务器永远停止在
ReadLine()
处,或者直到您的服务器停止运行,因为如果传入文本。见鬼,发送一大块没有换行符的文本


这可以简单到(使用C#vCurrent)

列出套接字=。。。
...
//(加入)
var newSocket=。。。
var reader=newstreamreader(…);//关于newSocket
sockets.Add((newSocket,reader));
// ...
foreach(套接字中的var对){
// ...
var socket=pair.socket;
var line=pair.reader.ReadLine();
如果(行!=null){…}
// ...
}

查看和,以及Stephen Cleary的文章。你的意思是,在从客户端发送的每条消息上,客户端应该发送以字节为单位的消息大小,然后当服务器收到该消息时,他将知道消息的大小,如果消息大小不相等,他将把消息的这一部分放到消息中,直到消息完成到该大小为止?是的,这就是那些答案和链接文章中推荐的解决方案。我已经在我的问题中添加了我的
Send
功能。这就是我获取发送字符串大小的方式吗?通过执行
var howManyBytes=json.Length*sizeof(Char)?你能给我举个例子,我的send函数应该是什么样子的,这样它就可以设置一个前缀,前缀的大小以发送字符串的字节为单位吗?你是否在循环中运行
Update
code?含义:单个套接字是否可以访问新的StreamReader(s,true)
两次?如果是这样的话:问题几乎可以肯定是您丢失了
StreamReader
缓冲的数据中的一些数据,并且您丢弃了这些数据-即它读取了一行的全部内容,下一行的部分内容非常感谢您的详细回答!您能告诉我如何使用StreamReader撕开套接字*的元组吗?我的意思是你能把它添加到你的答案中吗?我会把你的答案标记为一个答案,但我会使用消息框架。再次感谢你。这是一个展示好消息框架的好指南吗:?@TonyStark还有其他需要注意的事情:您当前正在检查套接字上的
.DataAvailable
,这会告诉您套接字上本地缓冲了多少数据,但是您可能已经在读卡器中缓冲了多行数据,所以不能仅仅因为
.DataAvailable就进行处理==0
可能导致错过消息(尤其是错过最终消息)。顺便说一句,没有简单的方法可以查看
StreamReader
中缓冲了什么。这使得根本不使用
StreamReader
和手动处理框架变得更加引人注目。是的,我想我会使用消息框架。你能检查一下我在链接中提供的指南吗?你觉得怎么样?使用这种方法好吗?@TonyStark坦率地说,我不打算看半小时的视频-我是一个关注文本的人,但从我所看到的:它使用
ArrayList
作为后台缓冲区,做了一些疯狂的奇怪事情,这是非常低效的-而且看起来它还使用了
BinaryFormatter
,这
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);
}
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) {...}
    // ...
}