*
Previous C#/.NET Core Coding Guidelines Entity-Framework Next

C#/.NET Communication & Protocols — Examples

walk through a modular, real-world-ready example that touches on serial communication, TCP/IP sockets, and protocol parsing in C#.

🧩 1. Serial Communication in C#

✅ Example: Basic Serial Port Setup

public class SerialDriver
{
    private SerialPort _port;

    public void Initialize(string portName, int baudRate = 9600)
    {
        _port = new SerialPort(portName, baudRate)
        {
            Parity = Parity.None,
            DataBits = 8,
            StopBits = StopBits.One,
            Handshake = Handshake.None,
            ReadTimeout = 2000,
            WriteTimeout = 2000
        };

        _port.DataReceived += OnDataReceived;
        _port.Open();
    }

    private void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        string data = _port.ReadLine();
        ParseProtocol(data);
    }

    public void Send(string message)
    {
        if (_port?.IsOpen == true)
            _port.WriteLine(message);
    }

    private void ParseProtocol(string raw)
    {
        // Example: parse a simple key-value protocol
        var parts = raw.Split('=');
        if (parts.Length == 2)
            Console.WriteLine($"Key: {parts[0]}, Value: {parts[1]}");
    }
}

Note: Need to install Nuget Package System.IO.Ports

🌐 2. TCP/IP Communication

✅ Example: TCP Client

using System.Net.Sockets;
using System.Text;
public class TcpClientDriver
{
    private TcpClient _client;
    private NetworkStream _stream;

    public void Connect(string ip, int port)
    {
        _client = new TcpClient(ip, port);
        _stream = _client.GetStream();
    }

    public void Send(string message)
    {
        byte[] data = Encoding.UTF8.GetBytes(message);
        _stream.Write(data, 0, data.Length);
    }

    public void Receive()
    {
        byte[] buffer = new byte[1024];
        int bytes = _stream.Read(buffer, 0, buffer.Length);
        string response = Encoding.UTF8.GetString(buffer, 0, bytes);
        ParseProtocol(response);
    }

    private void ParseProtocol(string raw)
    {
        // Reuse same parser logic or extend for TCP framing
        Console.WriteLine($"Received: {raw}");
    }
}

🧠 3. Protocol Parsing Best Practices

✅ Do This:

  • Define a clear protocol contract: Use structured formats like JSON, XML, or custom delimiters.
  • Validate input rigorously: Always check for malformed or unexpected data.
  • Use state machines for complex protocols: Especially when dealing with multi-frame or handshake-based communication.
  • Log raw and parsed data separately: Helps in debugging and auditing.
  • Use async I/O: Prevents blocking and improves scalability.

🚫 Avoid This:

  • Assuming fixed-length messages without framing or delimiters.
  • Ignoring encoding mismatches (UTF-8 vs ASCII).
  • Parsing without bounds checking—leads to buffer overflows or crashes.
  • Hardcoding protocol logic—use modular parsers or strategy patterns.
  • Skipping retries or timeouts—especially in noisy environments like RS-232.

🧱 Modular Architecture Tip

For scalable driver development:

  • Use vertical slice architecture: Each protocol or device type gets its own handler.
  • Implement IProtocolParser interface and inject parsers via DI for testability and extensibility.

Example interface

public interface IProtocolParser
{
    bool TryParse(string raw, out ParsedMessage result);
}

🧨 Common Protocol Parsing Errors

  • 1. Incorrect Framing or Delimiters

    Cause: Assuming fixed-length messages or failing to detect start/end markers.

    Impact: Misaligned reads, partial messages, or buffer overflows.

    Fix: Use framing strategies like STX/ETX markers, length-prefixed headers, or newline delimiters.

  • 2. Encoding Mismatches

    Cause: Mixing UTF-8, ASCII, or binary without explicit handling.

    Impact: Garbled data, failed deserialization, or silent corruption.

    Fix: Normalize encoding at the transport layer and validate before parsing.

  • 3. Stateful Protocol Mismanagement

    Cause: Ignoring handshake states, session tokens, or expected transitions.

    Impact: Invalid command execution, security holes, or dropped connections.

    Fix: Implement a finite state machine (FSM) to track protocol phases.

  • 4. Malformed or Unexpected Input

    Cause: No schema validation or loose parsing logic.

    Impact: Crashes, undefined behavior, or security vulnerabilities.

    Fix: Use strict parsers with schema enforcement (e.g., JSON schema, XML XSD, or custom validators).

  • 5. Buffer Mismanagement

    Cause: Reading too much or too little from the stream.

    Impact: Data truncation, overflow, or deadlocks.

    Fix: Always check buffer bounds and use circular buffers or stream parsers for continuous data.

  • 6. Versioning and Compatibility Issues

    Cause: Protocol changes without backward compatibility.

    Impact: Legacy clients fail, or newer features break older parsers.

    Fix: Embed version headers and use strategy patterns for parser dispatch.

  • 7. Concurrency and Race Conditions

    Cause: Parsing shared buffers across threads without locks.

    Impact: Data corruption or inconsistent state.

    Fix: Use thread-safe queues or async pipelines with proper synchronization.

  • 8. Silent Failures

    Cause: Swallowing exceptions or ignoring parse errors.

    Impact: Undetected bugs, data loss, or security risks.

    Fix: Log all parse failures with context and metrics. Use structured logging.

🧠 Strategic Tips for Resilient Parsing

  • Modular Parsers: Break down parsing into tokenization, validation, and transformation stages.
  • Test with Fuzzing: Use fuzzing tools to simulate malformed or edge-case inputs.
  • Telemetry Hooks: Track parse success/failure rates, latency, and payload sizes.
  • Replay Buffers: Store raw input for replay during debugging or test automation.
Back to Index
Previous C#/.NET Core Coding Guidelines Entity-Framework Next
*
*