2012-06-28 58 views
2

首先,我絕對不是網絡程序員。我嘗試做的是Java服務器和C#客戶端之間非常簡單的TCP/IP通信。不完整的消息(C#TCP/IP客戶端)

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(); 
      } 

的主要問題是,所有的消息都到達不完整的。這裏的日誌跟蹤:

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

而不是例如

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

我有點困惑,我需要一些幫助來解決這個問題。非常感謝你!

回答

2

TCP是面向流的連接,不是面向消息的。它沒有消息的概念。當你寫出你的序列化字符串時,它只會看到無意義的字節序列。 TCP可以自由地將該流分解成多個片段,並且它們將在客戶端以這些片段大小的塊被接收。在另一端重建整個消息取決於你。

在您的方案中,通常會發送消息長度前綴。這樣,客戶端首先讀取長度前綴,以便它可以知道傳入消息應該有多大。

我會認真考慮使用類似Google的Protocol Buffers這樣的方式來聲明消息,然後使用大小前綴選項對它們進行流式傳輸。好的一點是你定義了一組消息,然後使用可用的tools從消息定義中自動生成C++,Java,C#等代碼。這將有助於在語言之間使用一致的消息傳遞集。

1

一條消息(我的意思是任何數據)在通過套接字發送時,分爲幾個包。 打印每個收到的數據包時,您看不到您的整個消息。

您應該定義一個消息結尾字符串(類似於「。#。」)。在你收到這個序列之前,你需要連接你收到的消息。

這是什麼會話協議(即運行在TCP頂部的協議)。

希望這會有所幫助。

問候,Calil

0

看看這個例子...

的Java TCP服務器...

import java.net.*; 
import java.io.*; 

public class TcpServer 
{ 
    public static void main(String h[]) 
    { 
     try 
     { 
      ServerSocket serverSocket = new ServerSocket(1100); 
      Socket socket = serverSocket.accept(); 
      System.out.println("Client Accepted"); 
      BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
      System.out.println("Received: " + bufferedReader.readLine()); 
      PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()), true); 
      printWriter.println("Hello Theo. Welcome to socket programming."); 
     } catch (Exception e) 
     { 
      System.out.println(e); 
     } 
    } 
} 

C#TCP客戶端...

using System; 
using System.IO; 
using System.Net.Sockets; 

class Program 
{ 
    static void Main(string[] args) 
    { 
     try 
     { 
      var client = new TcpClient("localhost", 1100); 
      var stream = client.GetStream(); 
      var streamWriter = new StreamWriter(stream); 
      streamWriter.WriteLine("My name is Theo"); 
      streamWriter.Flush(); 
      var streamReader = new StreamReader(stream); 
      Console.WriteLine("Received: " + streamReader.ReadLine()); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine(ex); 
     } 

     Console.WriteLine("Press a key to continue."); 
     Console.ReadKey(); 
    } 
}