Byte Order Test Web

Link

UdpClient

public static void UdpClientTest()
{
    UdpClient udpClient = new UdpClient("192.168.2.52", 60000);
    string sendMsg = "Hello World";
    byte[] sendBytes = System.Text.Encoding.UTF8.GetBytes(sendMsg);
    udpClient.Send(sendBytes, sendBytes.Length);
    IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
    Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
    string returnData = Encoding.UTF8.GetString(receiveBytes);
    Console.WriteLine("This is the message you received: " + returnData.ToString());
    udpClient.Close();
}

public static void UdpClientTest()
{
    UdpClient udpClient = new UdpClient("192.168.2.52", 60000);
    MemoryStream memoryStream = new MemoryStream();
    BinaryWriter binaryWriterData = new BinaryWriter(memoryStream);
    binaryWriterData.Write(2);
    udpClient.Send(memoryStream.GetBuffer(), (int)memoryStream.Length);
    IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
    Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
    memoryStream = new MemoryStream(receiveBytes);
    BinaryReader binaryReader = new BinaryReader(memoryStream);
    int i = binaryReader.ReadInt32();
    Console.WriteLine("This is the message you received: " + i);
    udpClient.Close();
}

public static void UdpReceiveTest()
{
    UdpClient udpClient = new UdpClient(60001);
    IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
    Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
    string returnData = Encoding.UTF8.GetString(receiveBytes);
    string sendMsg = "Hello World";
    byte[] sendBytes = System.Text.Encoding.UTF8.GetBytes(sendMsg);
    udpClient.Send(sendBytes, sendBytes.Length, RemoteIpEndPoint);
    Console.WriteLine("This is the message you received: " + returnData.ToString());
    udpClient.Close();
}

MemoryStream & BinaryWriter

/// <summary>
/// Insert the response header and data length to the data package then send it to the client
/// </summary>
/// <param name="responseData"></param>
private void ResponseCommand(MemoryStream responseData)
{
    byte responseCommand =(byte)((int)this.requestCommand+128);
    ResponseCommand(responseCommand, responseData);
}

private void ResponseCommand(byte responseCommand, MemoryStream responseData)
{
    MemoryStream memoryStream = new MemoryStream();
    BinaryWriter binaryWriterData = new BinaryWriter(memoryStream);
    binaryWriterData.Write(responseCommand);
    binaryWriterData.Write(IPAddress.HostToNetworkOrder((short)responseData.Length));
    logger.Debug(string.Format("ResponseCommand: {0}-{1}", responseCommand, IPAddress.HostToNetworkOrder((short)responseData.Length)));
    if (responseData != null && responseData.Length > 0)
    {
        binaryWriterData.Write(responseData.ToArray());
    }
    binaryWriter.Write(memoryStream.ToArray());
}

public void ResponseOpenFrameGrabber()
{
    MemoryStream responseData = new MemoryStream();
    BinaryWriter binaryWriterData = new BinaryWriter(responseData);
    binaryWriterData.Write(IPAddress.HostToNetworkOrder(1));
    ResponseCommand(responseData);
}

NetworkToHostOrder

public SearchData RequestSaveReferencePointData()
{
    SearchData searchData = new SearchData();
    searchData.ModelID = IPAddress.NetworkToHostOrder(binaryReader.ReadInt32());
    searchData.ReferencePointX.X = BitConverter.ToSingle(BitConverter.GetBytes(IPAddress.NetworkToHostOrder(binaryReader.ReadInt32())), 0);
    searchData.ReferencePointX.Y = BitConverter.ToSingle(BitConverter.GetBytes(IPAddress.NetworkToHostOrder(binaryReader.ReadInt32())), 0);
    searchData.ReferencePointX.Z = BitConverter.ToSingle(BitConverter.GetBytes(IPAddress.NetworkToHostOrder(binaryReader.ReadInt32())), 0);
    searchData.ReferencePointXOffset = BitConverter.ToSingle(BitConverter.GetBytes(IPAddress.NetworkToHostOrder(binaryReader.ReadInt32())), 0);
    searchData.ReferencePointYOffsetX = BitConverter.ToSingle(BitConverter.GetBytes(IPAddress.NetworkToHostOrder(binaryReader.ReadInt32())), 0);
    searchData.ReferencePointZ.X = BitConverter.ToSingle(BitConverter.GetBytes(IPAddress.NetworkToHostOrder(binaryReader.ReadInt32())), 0);
    searchData.ReferencePointZ.Y = BitConverter.ToSingle(BitConverter.GetBytes(IPAddress.NetworkToHostOrder(binaryReader.ReadInt32())), 0);
    searchData.ReferencePointZ.Z = BitConverter.ToSingle(BitConverter.GetBytes(IPAddress.NetworkToHostOrder(binaryReader.ReadInt32())), 0);
    searchData.ReferencePointZOffset = BitConverter.ToSingle(BitConverter.GetBytes(IPAddress.NetworkToHostOrder(binaryReader.ReadInt32())), 0);
    return searchData;
}

MemoryStream & BinaryWriter & BinaryFormatter

BinaryFormatter不安全,不建议使用。

MemoryStream responseData = new MemoryStream();
BinaryWriter binaryWriterData = new BinaryWriter(responseData);
binaryWriterData.Write(IPAddress.HostToNetworkOrder(1));

MemoryStream ms = new MemoryStream();
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, obj);
byte[] arrBytes = ms.GetBuffer();
ms.Close();

如何判断客户端client已经关闭

TCP的Socket同行过程中,默认情况下,如果客户端自行关闭client,服务器是不清楚的,需要主动读取或者写入数据才能感知到。如调用NetworkStream.Read函数时,返回数据长度为0时,则为客户端关闭了该连接。

  1. Check for Data Availability: You can use the NetworkStream.DataAvailable property to check if there is data available to read. If the client has closed the connection, reading from the stream will return 0 bytes.
  2. Handle Exceptions: When the client closes the connection, attempting to read from or write to the stream will throw an IOException. You can catch this exception to detect the closure.

TcpClient

TcpClient.NoDelay

该属性默认为false,代表只有当缓存满时,才会把数据发出去。

SocketOptionName.KeepAlive

套接字本身是有一套心跳保活机制的(TCP Keepalive),不过默认的设置并不像我们一厢情愿的那样有效。在双方TCP套接字建立连接后(即都进入ESTABLISHED状态)并且在两个小时左右上层没有任何数据传输的情况下,这套机制才会被激活。

    var client = new TcpClient();
    client.Connect(Host, Port);
    Socket socket = client.Client;
    bool keepAlive = true;

    socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, keepAlive);

IOControlCode.KeepAliveValues

TcpClient newClient=myListener.AcceptTcpClient();//接受请求

newClient.Client.IOControl(IOControlCode.KeepAliveValues, KeepAlive(1, 30000, 10000), null);//设置Keep-Alive参数

private byte[] KeepAlive(int onOff, int keepAliveTime, int keepAliveInterval)
{
    byte[] buffer = new byte[12];
    BitConverter.GetBytes(onOff).CopyTo(buffer, 0);
    BitConverter.GetBytes(keepAliveTime).CopyTo(buffer, 4);
    BitConverter.GetBytes(keepAliveInterval).CopyTo(buffer, 8);
    return buffer;
}

SocketOptionName.KeepAlive

使用KeepAlive功能,底层socket连接会自动周期性的发送一个keep alive数据包。当一个 TCP 连接建立之后,启用 TCP Keepalive 的一端便会启动一个计时器,当这个计时器数值到达 0 之后(也就是经过tcp_keep-alive_time时间后,这个参数之后会讲到),一个 TCP 探测包便会被发出。这个 TCP 探测包是一个纯 ACK 包(RFC1122#TCP Keep-Alives规范建议:不应该包含任何数据,但也可以包含1个无意义的字节,比如0x0),其 Seq号 与上一个包是重复的,所以其实探测保活报文不在窗口控制范围内。

internal class Program
{
    static void Main(string[] args)
    {
        // Define the endpoint and create the socket
        IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, 11000);
        Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        try
        {
            // Bind the socket to the endpoint and start listening
            listener.Bind(endPoint);
            listener.Listen(10);

            Console.WriteLine("Waiting for a connection...");

            while (true)
            {
                // Accept incoming connection
                Socket handler = listener.Accept();

                // Enable keep-alive
                handler.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);

                // Handle the connection
                string data = null;
                byte[] bytes = new byte[1024];

                int bytesRec = handler.Receive(bytes);
                data += Encoding.ASCII.GetString(bytes, 0, bytesRec);

                Console.WriteLine("Text received: {0}", data);

                // Echo the data back to the client
                byte[] msg = Encoding.ASCII.GetBytes(data);
                handler.Send(msg);

                handler.Shutdown(SocketShutdown.Both);
                handler.Close();
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }

        Console.WriteLine("\nPress ENTER to continue...");
        Console.Read();
    }
}

import socket
import time

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.10.55',11000))
time.sleep(1000)
# s.close

日志文件夹

字节数组和结构体的相关转化

public static class MarshalHelper
{
    public static T ByteArrayToStruct<T>(byte[] byteArray) where T : struct
    {
        T obj = default;
        int size = Marshal.SizeOf(obj);

        if (byteArray.Length != size)
        {
            throw new ArgumentException($"Byte array size does not match the size of the struct {typeof(T)}");
        }

        IntPtr ptr = Marshal.AllocHGlobal(size);
        try
        {
            Marshal.Copy(byteArray, 0, ptr, size);
            obj = (T)Marshal.PtrToStructure(ptr, typeof(T));
        }
        finally
        {
            Marshal.FreeHGlobal(ptr);
        }

        return obj;
    }

    public static byte[] StructToByteArray<T>(T obj) where T : struct
    {
        int size = Marshal.SizeOf(obj);
        byte[] byteArray = new byte[size];

        IntPtr ptr = Marshal.AllocHGlobal(size);
        try
        {
            Marshal.StructureToPtr(obj, ptr, true);
            Marshal.Copy(ptr, byteArray, 0, size);
        }
        finally
        {
            Marshal.FreeHGlobal(ptr);
        }

        return byteArray;
    }
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack =1)]
public struct MyStruct
{
    public int IntegerValue;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)]
    public string StringValue;
}

MyStruct myStruct1 = new MyStruct
{
    IntegerValue = 12345,
    StringValue = "Hello, World!"
};
byte[] byteArray = new byte[54];
BitConverter.GetBytes(12345).CopyTo(byteArray, 0);
byte[] stringBytes = System.Text.Encoding.ASCII.GetBytes("Hello, World!");
Array.Copy(stringBytes, 0, byteArray, 4, stringBytes.Length);
MyStruct myStruct2 = ByteArrayToStruct<MyStruct>(byteArray);
byte[] bytes = StructToByteArray(myStruct1);