Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.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#_Sockets_Tcp_Client Server - Fatal编程技术网

C#TCP读取所有数据-服务器端问题

C#TCP读取所有数据-服务器端问题,c#,sockets,tcp,client-server,C#,Sockets,Tcp,Client Server,我正在使用C#v4.0(.Net Framework v4)开发一个简单的TCP服务器应用程序: 我想完成这两个步骤: 客户端向服务器发送消息1(客户端可以是.net或java应用程序) 服务器向客户端发回消息2,作为对消息1的响应 我的服务器出现问题,无法正确阅读邮件1,除非我使用以下不合适的解决方案之一: 1)使用只有1字节缓冲区的MemoryStream(工作正常但速度较慢): while(true) { TcpClient TcpClient=tcpListener.AcceptTcpC

我正在使用C#v4.0(.Net Framework v4)开发一个简单的TCP服务器应用程序:

我想完成这两个步骤:

  • 客户端向服务器发送消息1(客户端可以是.net或java应用程序)
  • 服务器向客户端发回消息2,作为对消息1的响应
  • 我的服务器出现问题,无法正确阅读邮件1,除非我使用以下不合适的解决方案之一:

    1)使用只有1字节缓冲区的MemoryStream(工作正常但速度较慢):

    while(true)
    {
    TcpClient TcpClient=tcpListener.AcceptTcpClient();
    NetworkStream NetworkStream=tcpClient.GetStream();
    MemoryStream MemoryStream=新的MemoryStream();
    int numberOfBytesRead=0;
    byte[]buffer=新字节[1];//在出现大消息时工作,但速度较慢
    做
    {
    numberOfBytesRead=networkStream.Read(buffer,0,buffer.Length);
    memoryStream.Write(缓冲区,0,numberOfBytesRead);
    }while(networkStream.DataAvailable);
    如果(memoryStream.Length>0)
    {
    字符串message1=新的StreamReader(memoryStream).ReadToEnd();
    如果(message1==“message1”)
    {
    使用(StreamWriter StreamWriter=新StreamWriter(网络流))
    {
    字符串message2=“message2”;
    streamWriter.Write(message2);
    streamWriter.Flush();
    }
    }
    }
    }
    
    示例:如果message1.Length==12501,并且我使用1024的缓冲区,则NetworkStream.Read()循环仅读取2048字节的message1,我认为NetworkStream.DataAvailable不会返回正确的值

    2)使用线程。从NetworkStream读取到缓冲区后睡眠(1000)(工作正常但速度较慢):

    while(true)
    {
    TcpClient TcpClient=tcpListener.AcceptTcpClient();
    NetworkStream NetworkStream=tcpClient.GetStream();
    MemoryStream MemoryStream=新的MemoryStream();
    int numberOfBytesRead=0;
    字节[]缓冲区=新字节[8192];
    做
    {
    numberOfBytesRead=networkStream.Read(buffer,0,buffer.Length);
    memoryStream.Write(缓冲区,0,numberOfBytesRead);
    Thread.Sleep(1000);//工作正常,但接收速度变慢
    }while(networkStream.DataAvailable);
    如果(memoryStream.Length>0)
    {
    字符串message1=新的StreamReader(memoryStream).ReadToEnd();
    如果(message1==“message1”)
    {
    使用(StreamWriter StreamWriter=新StreamWriter(网络流))
    {
    字符串message2=“message2”;
    streamWriter.Write(message2);
    streamWriter.Flush();
    }
    }
    }
    }
    
    3)使用StreamReader.ReadToEnd()并在发送消息1后关闭客户端的套接字(工作正常,但服务器无法使用消息2响应客户端):

    while(true)
    {
    TcpClient TcpClient=tcpListener.AcceptTcpClient();
    NetworkStream NetworkStream=tcpClient.GetStream();
    StreamReader StreamReader=新的StreamReader(networkStream,true);
    string message1=streamReader.ReadToEnd();//阻塞,直到客户端关闭其套接字
    如果(message1==“message1”)
    {
    使用(StreamWriter StreamWriter=新StreamWriter(网络流))
    {
    字符串message2=“message2”;
    streamWriter.Write(message2);//如果客户端关闭其套接字,服务器将无法发送此消息
    streamWriter.Flush();
    }
    }
    }
    
    4)使用StreamReader.ReadLine()循环并关闭客户端的套接字

    while(true)
    {
    TcpClient TcpClient=tcpListener.AcceptTcpClient();
    NetworkStream NetworkStream=tcpClient.GetStream();
    StreamReader StreamReader=新的StreamReader(networkStream);
    StringBuilder StringBuilder=新的StringBuilder();
    而(!streamReader.EndOfStream)
    {
    stringBuilder.AppendLine(streamReader.ReadLine());//阻塞,直到客户端关闭其套接字
    }
    string message1=stringBuilder.ToString();
    如果(message1==“message1”)
    {
    使用(StreamWriter StreamWriter=新StreamWriter(网络流))
    {
    字符串message2=“message2”;
    streamWriter.Write(message2);//如果客户端关闭其套接字,服务器将无法发送此消息
    streamWriter.Flush();
    }
    }
    }
    
    5)在message1前面加上长度前缀(可以工作,但需要客户端向消息中添加额外字节,这对现有java客户端不起作用)

    while(true)
    {
    TcpClient TcpClient=tcpListener.AcceptTcpClient();
    NetworkStream NetworkStream=tcpClient.GetStream();
    MemoryStream MemoryStream=新的MemoryStream();
    byte[]bufferMessageLength=新字节[4];//大小(int)
    networkStream.Read(bufferMessageLength,0,bufferMessageLength.Length);
    int messageLength=BitConverter.ToInt32(bufferMessageLength,4);
    byte[]bufferMessage=新字节[messageLength];
    networkStream.Read(bufferMessage,0,bufferMessage.Length);
    memoryStream.Write(缓冲区,0,bufferMessage.Length);
    如果(memoryStream.Length>0)
    {
    字符串message1=新的StreamReader(memoryStream).ReadToEnd();
    如果(message1==“message1”)
    {
    使用(StreamWriter StreamWriter=新StreamWriter(网络流))
    {
    字符串message2=“message2”;
    streamWriter.Write(message2);
    streamWriter.Flush();
    }
    }
    }
    }
    

    关于这些问题,在不使用上述解决方案的情况下从客户端读取所有数据的最佳方法是什么?

    而不是使用
    networkStream.DataAvailable
    在消息开头追加数据大小。例如,您的消息长度为1250
    public static void ReadStream(NetworkStream reader, byte[] data)
    {
        var offset = 0;
        var remaining = data.Length;
        while (remaining > 0)
        {
            var read = reader.Read(data, offset, remaining);
            if (read <= 0)
                throw new EndOfStreamException
                    (String.Format("End of stream reached with {0} bytes left to read", remaining));
            remaining -= read;
            offset += read;
        }
    }
    
    var bytesRead = 0;
    var offset = 0;
    TcpClient tcpClient = tcpListener.AcceptTcpClient();
    NetworkStream networkStream = tcpClient.GetStream();
    var bufferMessageSize = new byte[4]; // int32
    
    ReadStream(networkStream, bufferMessageSize);
    
    var messageSize = BitConverter.ToInt32(bufferMessageSize, 4); // bytesToRead
    
    var bufferMessage = new byte[messageSize];
    
    ReadStream(networkStream, bufferMessage);
    
    
    // Now Respond back Client here
    // networkStream.Write();