C#客户端/服务器问题

时间:2011-09-23 01:20:05

标签: c# tcp client-server tcpclient networkstream

我对这里发生的事情感到非常困惑。我一直在提供突破点,而我似乎无法理解。基本上,我有一个客户端和一个服务器。我希望客户端发送两个单独的数据字符串。从提交断点开始,我注意到我的客户端确实用适当的数据填充了两个字符串。但是,服务器永远不会看到第二个字符串。为什么会发生这种情况,我该如何解决?任何帮助都会非常感激!以下是我的代码:

服务器:

    private static void HandleClientComm(object client)
    {
        /** creating a list which contains DatabaseFile objects **/
        List<DatabaseFile> theDatabase = new List<DatabaseFile>();

        TcpClient tcpClient = (TcpClient)client;
        NetworkStream clientStream = tcpClient.GetStream();

        StringBuilder response = new StringBuilder();
        byte[] message = new byte[4096];
        int bytesRead;

        do
        {
            bytesRead = 0;

            try
            {
                /*do
                {
                    bytesRead = clientStream.Read(message, 0, message.Length);
                    response.Append(Encoding.ASCII.GetString(message, 0, bytesRead));
                } while (clientStream.DataAvailable);*/

当我将此注释代码更改为 bytesRead = clientStream.Read(message,0,4096); 我得到一个IOException错误,其内容如下:无法将数据写入传输连接:远程主机强制关闭现有连接。因此,我将其更改为do while循环。如何解决此IOException并接受第二个字符串?

                ASCIIEncoding encoder = new ASCIIEncoding();
                String file = encoder.GetString(message, 0, bytesRead);
                Menu.Insert(theDatabase, file); 
            }
            catch (Exception)
            {
                // A socket error has occured
                break;
            }

            if (bytesRead == 0)
            {
                // The client has disconnected from the server
                break;
            }
        } while (clientStream.DataAvailable);

        // Release connections
        clientStream.Close();
        tcpClient.Close();
    }

客户:

    static void Main(string[] args)
    {
        TcpClient client = new TcpClient();

        IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8888);

        client.Connect(serverEndPoint);

        NetworkStream clientStream = client.GetStream();
        NetworkStream clientStream2 = client.GetStream();

        ASCIIEncoding encoder = new ASCIIEncoding();
        ASCIIEncoding encoder2 = new ASCIIEncoding();
        String text = System.IO.File.ReadAllText("FirstNames.txt");
        String text2 = System.IO.File.ReadAllText("LastNames.txt");

        byte[] buffer = encoder.GetBytes(text);

        Console.ReadLine(); 
        clientStream.Write(buffer, 0, buffer.Length);
        clientStream.Flush();
        Console.ReadLine();

        byte[] buffer2 = encoder2.GetBytes(text2);

        clientStream2.Write(buffer2, 0, buffer2.Length);
        clientStream2.Flush();
        Console.ReadLine(); 
    }
}

3 个答案:

答案 0 :(得分:2)

因为while (clientStream.DataAvailable)在第一次客户电话后不再为真。

答案 1 :(得分:2)

客户端和服务器之间的通信发生如下(请注意,步骤的顺序仅用于说明目的,运行时的实际顺序可能不同):

  1. 客户:client.Connect(serverEndPoint)
    服务器:HandleClientComm(newClient)

  2. 客户:clientStream.Write(buffer, 0, buffer.Length)
    服务器:bytesRead = clientStream.Read(message, 0, message.Length)
    请注意,Read无法保证读取整个邮件。只返回到目前为止收到的部分是完全可以的

  3. 客户:Console.ReadLine()
    服务器:while (clientStream.DataAvailable)
    流上没有数据 - 客户端没有发送任何数据。即使没有ReadLine,也可能发生这种情况 - 客户端再次发送数据之前有一段时间

  4. 服务器:tcpClient.Close()

  5. 客户:clientStream2.Write(buffer2, 0, buffer2.Length)
    您可以在此处获得例外 - 取决于服务器是否已关闭连接,无论如何服务器都不再阅读。
  6. 您需要定义自己的服务器和客户端将遵守的消息协议。例如,您可以让客户端在完成发送后关闭连接:

    <强>客户端:

    using (var client = new TcpClient("localhost", 8888))
    using (var clientStream = client.GetStream())
    {
        var buffer = Encoding.ASCII.GetBytes( File.ReadAllText("FirstNames.txt") );
        clientStream.Write(buffer, 0, buffer.Length);
    
        buffer = Encoding.ASCII.GetBytes( File.ReadAllText("LastNames.txt") );
        clientStream.Write(buffer, 0, buffer.Length);
    }
    

    服务器

    using (var tcpClient = (TcpClient)client)
    using (var clientStream = tcpClient.GetStream())
    {
        // Store everything that the client sends.
        // This will work if the client closes the connection gracefully
        // after sending everything
    
        var receivedData = new MemoryStream();
        clientStream.CopyTo(receivedData);
    
        var rawBytes = receivedData.ToArray();
        var file = Encoding.ASCII.GetString(rawBytes, 0, rawBytes.Length);
    
        Menu.Insert(theDatabase, file);
    }
    

    协议很简单,可能适合您的情况。但是,它存在一些问题,应该在生产代码中解决(例如,如果客户端发送过多数据,耗尽服务器内存,如果客户端在不关闭连接的情况下停止发送会怎么样,等等)。

答案 2 :(得分:1)

您正在退出服务器中的client-recv循环,因为DatAvailable为false。这意味着如果客户端要发送一个数据帧(您使用的数据)并暂停,那么您的服务器将在那时看不到可用的数据并断开连接,即使一秒钟之后客户端的另一帧数据即将到来几乎总是,对话框的结束基于传递的数据的内容。你当然可以永远不要试图依赖DataAvailable碰巧错误的事实。

作为后续行动,如果您提供有关所使用协议的更多信息,我们可以提供更多帮助。例如,如果prototcol是最后两个字符串与CR / LF一起发送的那么服务器循环应该检查缓冲区以确定何时断开连接。