如何在C#中按包读取TCP数据包?解决Unity接收Matlab数据拼接问题
Hey there! That packet concatenation issue you're seeing is totally normal for TCP—it's a stream-based protocol, not message-based, so it groups small packets together for efficiency, or holds onto data if the receiver isn't reading fast enough. Let's fix this by implementing proper packet framing so Unity can reliably read individual "a" or "b" messages.
Here are two straightforward, reliable methods to solve this:
Method 1: Use a Delimiter to Mark Packet Boundaries
The simplest approach is to add a unique delimiter (like a newline \n) after each "a" or "b" in your MATLAB sends. Unity will then buffer incoming data and split it at the delimiter to get individual packets.
Unity C# Implementation
using System.Text; using UnityEngine; public class TCPClient : MonoBehaviour { private string _receiveBuffer = ""; private const string PacketDelimiter = "\n"; // Assign your target object in the Inspector public GameObject targetObject; // Your coherence variable, now properly updated private string coherence; // This method gets called when new data arrives from TCP private void OnDataReceived(byte[] data, int bytesRead) { // Convert incoming bytes to string and add to buffer _receiveBuffer += Encoding.ASCII.GetString(data, 0, bytesRead); // Process all complete packets in the buffer while (_receiveBuffer.Contains(PacketDelimiter)) { int delimiterIndex = _receiveBuffer.IndexOf(PacketDelimiter); // Extract the full, single packet (exclude the delimiter) string fullPacket = _receiveBuffer.Substring(0, delimiterIndex); // Trim the buffer to remove the processed packet _receiveBuffer = _receiveBuffer.Substring(delimiterIndex + PacketDelimiter.Length); // Handle the packet ProcessCoherencePacket(fullPacket); } } private void ProcessCoherencePacket(string packet) { coherence = packet; Debug.Log($"Received valid coherence value: {coherence}"); // Update object color based on the received value Renderer objectRenderer = targetObject.GetComponent<Renderer>(); if (coherence == "a") { objectRenderer.material.color = Color.red; } else if (coherence == "b") { objectRenderer.material.color = Color.blue; } } // Rest of your TCP connection code (Connect, Listen, etc.) goes here }
MATLAB Implementation
Add the delimiter to each send call:
% Assuming 'tcpObj' is your established tcpclient connection send(tcpObj, 'a\n', 'ASCII'); % Send "a" plus newline delimiter send(tcpObj, 'b\n', 'ASCII'); % Send "b" plus newline delimiter
Method 2: Fixed-Length Packets
Since your messages are always exactly 1 character (1 byte in ASCII), you can configure Unity to read exactly 1 byte at a time. This works great for fixed-size messages.
Unity C# Implementation
using System.Text; using System.Collections.Generic; using UnityEngine; public class TCPClient : MonoBehaviour { private List<byte> _receiveBuffer = new List<byte>(); private const int PacketSize = 1; // Each packet is 1 byte public GameObject targetObject; private string coherence; private void OnDataReceived(byte[] data, int bytesRead) { // Add incoming bytes to buffer _receiveBuffer.AddRange(data[0..bytesRead]); // Process all complete fixed-size packets while (_receiveBuffer.Count >= PacketSize) { // Extract exactly 1 byte for the packet byte[] packetBytes = _receiveBuffer.GetRange(0, PacketSize).ToArray(); // Remove processed bytes from buffer _receiveBuffer.RemoveRange(0, PacketSize); // Convert to string and handle string packet = Encoding.ASCII.GetString(packetBytes); ProcessCoherencePacket(packet); } } // Reuse the same ProcessCoherencePacket method from Method 1 here private void ProcessCoherencePacket(string packet) { coherence = packet; Debug.Log($"Received valid coherence value: {coherence}"); Renderer objectRenderer = targetObject.GetComponent<Renderer>(); if (coherence == "a") { objectRenderer.material.color = Color.red; } else if (coherence == "b") { objectRenderer.material.color = Color.blue; } } // Rest of your TCP connection code goes here }
MATLAB Implementation
Just send the single character directly (no delimiter needed):
send(tcpObj, 'a', 'ASCII'); send(tcpObj, 'b', 'ASCII');
Key Notes
- Keep encoding consistent: Use ASCII (or UTF-8) in both MATLAB and Unity to avoid string conversion errors.
- Buffer management: Make sure you're trimming the buffer after processing packets to prevent memory bloat over time.
- Scalability: If you ever need to send longer messages later, the delimiter method is more flexible—just pick a delimiter that won't appear in your actual data (e.g.,
\r\nor a unique sequence like###END###).
内容的提问来源于stack exchange,提问作者Yannick_Da

