【问题标题】:Different data written to the server are becoming appended to become a single string写入服务器的不同数据被附加为单个字符串
【发布时间】:2023-03-21 15:15:01
【问题描述】:

注意参考this link

我写这个类是为了在服务器端用作代理,在客户端用作客户端。

我目前的源码如下:

public class ClientClass : IDisposable
{
    private string Host { get; set; }
    private int Port { get; set; }

    public bool IsConnected { private set;  get; }

    public TcpClient Tcp { get; private set; }

    private System.Net.Sockets.NetworkStream stream;

    public ClientClass()
    {
        IsConnected = false;
    }

    //constructor for server program.
    public ClientClass(TcpListener listener)
    {
        Tcp = listener.AcceptTcpClient();

        Host = ((IPEndPoint)Tcp.Client.RemoteEndPoint).Address.ToString();
        Port = ((IPEndPoint)Tcp.Client.LocalEndPoint).Port;

        IsConnected = true;

        stream = Tcp.GetStream();
    }

    //constructor for client.
    public ClientClass(string host, int port)
    {
        Host = host;
        Port = port;
    }

    public string Read()
    {
        if (IsConnected)
        {
            byte[] buffer = new byte[Tcp.ReceiveBufferSize];//create a byte array
            int bytesRead = stream.Read(buffer, 0, Tcp.ReceiveBufferSize);//read count
            string str = Encoding.ASCII.GetString(buffer, 0, bytesRead);//convert to string
            return str.TrimEnd(new char[] {'\r', '\n'});//remove CR and LF
        }
        else
        {
            throw new Exception("Client " + ID + " is not connected!");
        }
    }

    public void Write(string str)
    {
        if (IsConnected)
        {
            str = str + Constants.CRLF;// add CR and LF
            byte[] bytesToSend = ASCIIEncoding.ASCII.GetBytes(str);
            stream.Write(bytesToSend, 0, bytesToSend.Length);
            stream.Flush();
        }
        else
        {
            throw new Exception("Client " + ID + " is not connected!");
        }
    }

    public bool Connect()
    {
        if (IsConnected == false)
        {
            IsConnected = true;

            Tcp = new TcpClient(Host, Port);

            stream = Tcp.GetStream();

            return true;
        }

        return false;
    }

    public bool Disconnect()
    {
        if (IsConnected)
        {
            if (Tcp != null)
            {
                //stream.Flush();
                stream.Close();
                //Tcp.GetStream().Flush();
                //Tcp.GetStream().Close();
                Tcp.Close();

                return true;
            }
        }

        return false;
    }

    #region dispose pattern
    // Flag: Has Dispose already been called?
    bool disposed = false;

    // Public implementation of Dispose pattern callable by consumers.
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    // Protected implementation of Dispose pattern.
    protected virtual void Dispose(bool disposing)
    {
        if (disposed)
            return;

        if (disposing)
        {
            // Free any other managed objects here
            if (stream != null)
            {
                stream.Flush();
                stream.Close();
                stream.Dispose();
                stream = null;
            }
            if (Tcp != null)
            {
                if (Tcp.Connected)
                {
                    Tcp.Client.Disconnect(false);
                    Tcp.Client.Close();
                    Tcp.Client.Dispose();
                    Tcp.Client = null;

                    //Tcp.GetStream().Flush();
                    //Tcp.GetStream().Close();
                    Tcp.Close();                        
                    Tcp = null;
                }
            }
        }

        // Free any unmanaged objects here.
        // ...
        disposed = true;
    }

    ~ClientClass()
    {
        Dispose(false);
    }
    #endregion
}

这段代码我面临的问题是:

ClientClass client = new ClientClass(...);
client.Write("1");
client.Write("2");
client.Write("hello");

只作为一个输入到达另一端:

"12hello"

,而不是三个单独的输入 {“1”、“2”和“hello”}。

我该如何解决这个问题?


【问题讨论】:

    标签: c# tcp tcpclient tcplistener


    【解决方案1】:

    TCP 是流协议,而不是数据包协议。您所保证的只是相同顺序的相同字节(或套接字故障),不是组的组成。所以:除此之外的任何内容您需要自己添加。对于基于文本的协议,一种常见的方法可能是在每个逻辑负载之后放置一个换行符 (\n),然后在解码时查找相同的内容。对于二进制协议,长度前缀更为常见。

    【讨论】:

    • 如何在另一端拆分数据?
    • @user366312 这真的取决于服务器的严重程度;对于临时系统,您可以在NetworkStream 上使用StreamReader,并在循环中使用ReadLine() / ReadLineAsync()(您也可以在另一端使用StreamWriterWriteLine())。对于“严肃”的服务器,我需要大约 4 个小时来完成大部分内容......
    • 但是,还有一个问题:我的旧源代码也是使用 TCP 协议的,但当时我没有遇到这个问题。 为什么?
    • @user366312 可能是时间的侥幸结合“nagle”(即 TCP 延迟启发式);您可能会发现添加socket.NoDelay = true 使其行为与以前非常相似,但它仍然从根本上被破坏了;它通常工作得“足够好”;同样,TCP 需要在您的代码中构建 - 您不能依赖交付细节
    猜你喜欢
    • 2013-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多