English 中文(简体)
NetworkStream dirty duringuser/server TCP communication
原标题:NetworkStream dirty during client/server TCP communication
  • 时间:2012-01-15 10:19:45
  •  标签:
  • c#
  • tcpclient

I ve both a client and a server communicating through TCP. The client uses the NetworkStream to send info to the server that reads it back, then the process continues until the user wants to exit and close the connection. The problem is that the NetworkStream is dirty with a previous write. So let s suppose the client sends the string "aa "during the first time, and "b" during the second. On the second read the server will get "ba". What s missing here? Shouldn t the NetworkStream be consumed during the server reads? Here`s the relevant code ...

服务器

        while (true)
        {
            try
            {
                NetworkStream clientStream = tcpClient.GetStream();
                bytesRead = clientStream.Read(messageBytes, 0, messageBytes.Length);
            }
            catch (Exception ex)
            {
                LogToConsole(clientEndPoint, String.Format("[ERROR] Exception: {0}", ex.Message));
                break;
            }

            if (bytesRead == 0)
            {
                LogToConsole(clientEndPoint, "Client has disconnected");
                break;
            }

            messageCounter++;
            string message = Encoding.ASCII.GetString(messageBytes);
            message = message.Substring(0, message.IndexOf(  ));
            LogToConsole(clientEndPoint, String.Format(" >> [{0}] Message received: {1}", messageCounter, message));
        }

CLIENT

            string infoToSend = null;
            do
            {
                Console.Write(" >> Info to send: ");
                infoToSend = Console.ReadLine();

                if (!String.IsNullOrEmpty(infoToSend))
                {
                    NetworkStream serverStream = client.GetStream();
                    byte[] buffer = Encoding.ASCII.GetBytes(infoToSend);
                    serverStream.Write(buffer, 0, buffer.Length);
                    serverStream.Flush();
                }
            } while (!String.IsNullOrEmpty(infoToSend));

SOLUTION

正如道格拉斯所指出的,缓冲(messageBytes)与先前的一段话相左。 我最后用这一服务器代码(我贴出整个代码,因为这可能对其他人有用):

namespace Gateway
{
    class Program
    {
        static void Main(string[] args)
        {
            int requestCount = 0;

            TcpListener serverSocket = new TcpListener(IPAddress.Any, 8888);
            serverSocket.Start();
            LogToConsole("服务器 Started. Waiting for clients ...");

            while ((true))
            {
                try
                {
                    TcpClient client = serverSocket.AcceptTcpClient();
                    requestCount++;
                    LogToConsole(String.Format("Connection from {0} accepted. Request #{1}", client.Client.RemoteEndPoint.ToString(), requestCount));

                    Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientConnection));
                    clientThread.IsBackground = true;
                    clientThread.Start(client);
                    LogToConsole(String.Format("Thread #{0} created to handle connection from {1}", clientThread.ManagedThreadId, client.Client.RemoteEndPoint.ToString()));
                    LogToConsole("Waiting for next client ...");
                }
                catch (Exception ex)
                {
                    LogToConsole(ex.ToString());
                    break;
                }
            }
        }

        static void HandleClientConnection(object client) 
        {
            TcpClient tcpClient = (TcpClient)client;

            byte[] messageBytes = new byte[1024];
            int bytesRead;
            int messageCounter = 0;

            string clientEndPoint = tcpClient.Client.RemoteEndPoint.ToString();

            while (true)
            {
                try
                {
                    NetworkStream clientStream = tcpClient.GetStream();
                    bytesRead = clientStream.Read(messageBytes, 0, messageBytes.Length);
                }
                catch (Exception ex)
                {
                    LogToConsole(clientEndPoint, String.Format("[ERROR] Exception: {0}", ex.Message));
                    break;
                }

                if (bytesRead == 0)
                {
                    LogToConsole(clientEndPoint, "Client has disconnected");
                    break;
                }

                messageCounter++;
                string message = Encoding.ASCII.GetString(messageBytes, 0, bytesRead);
                LogToConsole(clientEndPoint, String.Format(" >> [{0}] Message received: {1}", messageCounter, message));
            }

            LogToConsole(clientEndPoint, "Closed connection to client");
            tcpClient.Close();
        }

        static void LogToConsole(string clientEndPoint, string message)
        {
            int threadId = Thread.CurrentThread.ManagedThreadId;
            string time = DateTime.Now.ToString("HH:mm:ss");
            Console.WriteLine("{0} [{1}, {2}] {3}", time, threadId, clientEndPoint, message);
        }

        static void LogToConsole(string message)
        {
            int threadId = Thread.CurrentThread.ManagedThreadId;
            string time = DateTime.Now.ToString("HH:mm:ss");
            Console.WriteLine("{0} [{1}] {2}", time, threadId, message);
        }
    }
}
最佳回答
string message = Encoding.ASCII.GetString(messageBytes);

上述电话每次都标出整个缓冲,尽管每个电文只写到第一个n>(n是电文长度)。 你的第一份电文“a”是由缓冲带头两部书写的。 你的第二个信息,即“b”,仅是第一个直截了字,第一个字不提,而第二个字不提。 因此,在你第二次发出电文后,缓冲似乎含有“战争”。

你们可以通过将上述呼吁改为:

string message = Encoding.ASCII.GetString(messageBytes, 0, bytesRead);

然而,你的代码仍易受另一个问题的影响:NetworkStream.Read 仅读于现有数据。 如果客户仍在发送,则可能退回部分信息。 因此,您的服务器可将这两条电文改为“a”和“ab”。

在您的情形下,由于你似乎只发送了单行文本电文,你可在服务器和用户的<代码>StreamReader和上填写<>。 然后,简单叫<代码>。 服务器上的ReadLine 和 页: 1 <代码>ReadLine将随时读到,直至其有新线,并在到达下游时将返回<代码>null。

服务器:

using (NetworkStream clientStream = tcpClient.GetStream())
using (StreamReader reader = new StreamReader(clientStream))
{
    while (true)
    {
        message = reader.ReadLine();

        if (message == null)
        {
            LogToConsole(clientEndPoint, "Client has disconnected");
            break;
        }

        messageCounter++;
        LogToConsole(clientEndPoint, String.Format(" >> [{0}] Message received: {1}", messageCounter, message));
    }
}

Client:

using (NetworkStream serverStream = client.GetStream())
using (StreamWriter writer = new StreamWriter(serverStream))
{
    do
    {
        Console.Write(" >> Info to send: ");
        infoToSend = Console.ReadLine();

        if (!String.IsNullOrEmpty(infoToSend))
            writer.WriteLine(infoToSend);

    } while (!String.IsNullOrEmpty(infoToSend));
}

This solution will not work if your client can send newlines within your messages.

问题回答

暂无回答




相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签