不完整的消息(C#TCP/IP客户端) [英] Incomplete messages (C# TCP/IP Client)

查看:71
本文介绍了不完整的消息(C#TCP/IP客户端)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我绝对不是网络程序员.我想做的是在Java服务器和C#客户端之间进行非常简单的TCP/IP通信.

First of all, I'm absolutely not a network programmer. What I try to do, is a very simple TCP/IP communication between a Java server and a C# client.

Java服务器:

 public void run(){   
try {
       // Open server socket
       _server = new ServerSocket(SERVER_PORT);
       _client = _server.accept();
                System.out.println("ComInterface: client connected.");
                // Wait for a client data output stream
                while(true){

                    // Receive message from client
                    BufferedReader is =
                            new BufferedReader(new InputStreamReader(_client.getInputStream()));
                    msg = is.readLine();

                    // Process message
                    if(msg!=null){
                        System.out.println("ComInterface: Message Received : <" + msg + ">.");
                        processMessage(msg); // Independant method
                    }
                    else{
                        System.out.println("ComInterface: client closed connection.");
                        _client.close();
                        _client = _server.accept();
                        System.out.println("ComInterface: client connected.");
                    }

                }

            } catch (IOException e) {
                e.printStackTrace();
            }
}

public void sendMessage(String msg){
        try {

            // Out stream
            DataOutputStream os = new DataOutputStream(_client.getOutputStream());

            os.writeBytes((String)(msg+"\n"+(char)13));
            os.flush();
            System.out.println("ComInterface: Message <" + msg + "> sent");

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }   
    }

这是C#客户端:

public class ComInterface : MonoBehaviour
    {
        public const String SERVER_IP = "127.0.0.1"; // Localhost
        public const int PORT = 1100; // Default port 
        public const int READ_BUFFER_SIZE = 5000; // 4.8828125 kilobytes

        private TcpClient _client;
        private ASCIIEncoding _asen;
        private byte[] _readBuffer;
        private String _msg;

        public Boolean connected { get; internal set; } // setter is for internal use only

        /**
         * Initialize internal variables (buffer, socket...)
         */
        public ComInterface()
        {
            connected = false;
            _client = new TcpClient();
            _asen = new ASCIIEncoding();
            _readBuffer = new Byte[READ_BUFFER_SIZE];
            _msg = String.Empty;
        }

        /**
         * Connect to server at SERVER_IP:PORT
         * Return true if connection was a success, or false if failure.
         */
        public Boolean Connect()
        {
            try
            {

                _client.Connect(SERVER_IP, PORT);
                connected = true;
                Array.Clear(_readBuffer, 0, _readBuffer.Length);
                Debug.Log("TCPClient: <Connect> Connected to the server");
                // Start an asynchronous read invoking ReceiveComMessage
                _client.GetStream().BeginRead(_readBuffer, 0, READ_BUFFER_SIZE, new AsyncCallback(ReceiveComMessage), _client.GetStream());
            }
            catch (Exception ex)
            {
                Debug.Log("TCPClient: <Connect> Cannot connect to the server - " + ex.Message);
                connected = false;
            }
            // Return connection state
            return connected;
        }

 /**
         * Received a message from Communicator
         */
        private void ReceiveComMessage(IAsyncResult ar)
        {
            int BytesRead;
            String msg;
            try
            {
                BytesRead = _client.GetStream().EndRead(ar);
                if (BytesRead < 1)
                {
                    // if no bytes were read server has close.  
                    Debug.Log("TCPClient: <ReceiveComMessage> The server has closed (BytesRead<1)");
                    this.Disconnect();
                    return;
                }
                // Convert the byte array the message was saved into,
                msg = Encoding.ASCII.GetString(_readBuffer);
                Debug.Log("C# Message: \"" + msg + "\""); // Output example in log below
                BytesRead = 0;
                Array.Clear(_readBuffer, 0, _readBuffer.Length);

                // Start a new asynchronous read into readBuffer.
                _client.GetStream().BeginRead(_readBuffer, 0, READ_BUFFER_SIZE, new AsyncCallback(ReceiveComMessage), _readBuffer);

            }
            catch (Exception ex)
            {
                Debug.Log("TCPClient: <ReceiveComMessage> The server has closed (Exception):" + ex.Message + " see " + ex.StackTrace);
                this.Disconnect();
            }

主要问题是所有消息到达时均不完整.这是日志跟踪:

The main problem is that all the message are arriving incomplete. Here's the log trace:

C#: Message "{
C#: Message ""sender":"Bob"",
C#: Message ""recipient":",
etc...

而不是例如

C#: Message "{"sender":"Bob","recipient":[1,2,3]}"

我有点困惑,需要一些帮助来解决此问题.非常感谢你!

I'm a bit confused and I'd need some help to resolve this. Thank you very much!

推荐答案

TCP 是流面向连接,而不是面向消息.它没有消息的概念.当您写出序列化的字符串时,它只会看到无意义的字节序列.TCP可以自由地将流分解为多个片段,它们将在客户端以这些片段大小的块形式接收.您需要在另一端重建整个消息.

TCP is a stream-oriented connection, not message-oriented. It has no concept of a message. When you write out your serialized string, it only sees a meaningless sequence of bytes. TCP is free to break up that stream up into multiple fragments and they will be received at the client in those fragment-sized chunks. It is up to you to reconstruct the entire message on the other end.

在您的情况下,通常会发送一条消息长度前缀.这样,客户端首先读取了长度前缀,这样便可以知道传入消息应该有多大.

In your scenario, one would typically send a message length prefix. This way, the client first reads the length prefix so it can then know how large the incoming message is supposed to be.

我会认真考虑使用类似Google的协议缓冲区之类的方法来声明您的邮件,然后使用大小前缀选项将其流式传输.令人高兴的是,您一次定义了一组消息,然后使用可用的工具从消息定义自动生成C ++,Java,C#等代码.这将有助于在各种语言之间使用一致的消息传递集.

I would seriously consider using something like Google's Protocol Buffers as a good way of declaring your messages and then streaming them with the size prefix option. The nice thing is that you define your set of messages once and then use the available tools to automatically generate C++, Java, C#, etc code from the message definitions. This will help in having a consistent messaging set that works between languages.

这篇关于不完整的消息(C#TCP/IP客户端)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆