C# 如何使用Node和C通过TCP向客户端发送简单UInt#

C# 如何使用Node和C通过TCP向客户端发送简单UInt#,c#,node.js,tcp,C#,Node.js,Tcp,我使用一个节点服务器向Unity中的客户端发送一个简单的16位Int。Unity客户端有一个C#客户端脚本,用于连接到节点服务器并读取值 我使用的代码传递一个字符串,因此我将Int转换为字符串,然后在客户端上再次转换。我宁愿将值作为UInt16传递。。。首先,这是否更有效率?我如何在客户机上传递和转换它 以下是节点代码: server.on('connection', function(socket) { console.log('A new connection has been es

我使用一个节点服务器向Unity中的客户端发送一个简单的16位Int。Unity客户端有一个C#客户端脚本,用于连接到节点服务器并读取值

我使用的代码传递一个字符串,因此我将Int转换为字符串,然后在客户端上再次转换。我宁愿将值作为UInt16传递。。。首先,这是否更有效率?我如何在客户机上传递和转换它

以下是节点代码:

server.on('connection', function(socket) {
    console.log('A new connection has been established.');

    // Now that a TCP connection has been established, the server can send data to
    // the client by writing to its socket.
    
    if (sensor != null){
        sensor.on("change", value => {
            socket.write(value.toString());
        });
    }

    // The server can also receive data from the client by reading from its socket.
    socket.on('data', function(chunk) {
        console.log(`Data received from client: ${chunk.toString()}`);
    });

    // When the client requests to end the TCP connection with the server, the server
    // ends the connection.
    socket.on('end', function() {
        console.log('Closing connection with the client');
    });

    // Don't forget to catch error, for your own sake.
    socket.on('error', function(err) {
        console.log(`Error: ${err}`);
    });
});
这是统一的
C#
代码:

socketConnection = new TcpClient("localhost", 8080);
            Byte[] bytes = new Byte[1024];
            while (true)
            {
                using (NetworkStream stream = socketConnection.GetStream())
                {
                    int length;
                    // Read incoming stream into byte array
                    while ((length = stream.Read(bytes, 0, bytes.Length)) != 0)
                    {
                        var incomingData = new byte[length];

                        //Debug.Log(incomingData.GetValue(0));

                        //int value = Convert.ToUInt16(incomingData);
                        //Debug.Log(value);

                        Array.Copy(bytes, 0, incomingData, 0, length);
                        // Convert byte array to string message.                        
                        string serverMessage = Encoding.ASCII.GetString(incomingData);
                        int value = Int16.Parse(serverMessage);
                        Debug.Log(value);
                    }
                }
            }
我需要进行一些重构,但一般来说,这可以传递一个
字符串
。传递
UInt16
无效。非常感谢您的帮助

我宁愿将值作为UInt16传递。。。首先,这是否更有效率

是的,但是使用基于文本的协议而不是二进制协议有很多优点:即,与二进制协议相比,调试和检查基于文本的协议要容易得多。例如,HTTP是基于文本的(HTTP/2是一种二进制协议,但这只是因为Google想对其进行超优化,这在他们的规模上是有意义的,但对于绝大多数使用基于文本的协议的应用程序来说,这更有意义)

我如何在客户机上传递和转换它

困难地:

  • 在JavaScript中使用特定的数字类型比较困难,因为JavaScript只有
    number
    类型,甚至不是整数类型。JavaScript[确实有类型化缓冲区][1],但这是一个高级主题

  • 当处理多字节二进制整数时,需要处理多字节值的“网络顺序”,也称为endianness。大多数C#.NET环境都是“小端”的,但惯例是在线路上总是使用大端格式

  • TCP只在系统认为它是最佳的时候发送数据包(因为每个TCP数据包都有很多开销),但是默认情况下,在系统缓冲了大量的2字节值之前,发送单个的2字节值实际上不会被发送,否则您将不得不强制刷新网络堆栈。请注意,使用基于文本的协议也有同样的问题,但至少对于基于文本的协议,概念上的浪费更少

对于发送单个16位整数值,最好还是使用文本协议

…但如果你坚持:

server.on('connection', function(socket) {
    console.log('A new connection has been established.');

    if (sensor != null){
        sensor.on("change", value => {
            
            if( typeof value !== 'number' ) {
                throw new Error( "value must be a number." );
            }
            if( value < 0 || value > 65535 || Math.floor( value ) !== value ) {
                throw new Error( "value must be a 16-bit unsigned integer." );
            }

            const buffer = new Uint8Array( 2 );

            const hi = ( value >> 8 ) & 0xFF;
            const lo = ( value      ) & 0xFF;
            buffer.set( [ hi, lo ] ); // Big-Endian Order.

            const didFlush = socket.write( buffer );
            if( !didFlush )  console.log('Data did not send immediately.');
        });
    }

    // [...]

});
server.on('connection',函数(socket){
log('已建立新连接');
如果(传感器!=null){
传感器打开(“更改”,值=>{
如果(值的类型!=='number'){
抛出新错误(“值必须是数字”);
}
如果(值<0 | |值>65535 | |数学地板(值)!==值){
抛出新错误(“值必须是16位无符号整数。”);
}
const buffer=新的Uint8Array(2);
常量hi=(值>>8)&0xFF;
常量lo=(值)&0xFF;
set([hi,lo]);//大端顺序。
const didFlush=socket.write(缓冲区);
if(!didFlush)console.log('数据没有立即发送');
});
}
// [...]
});
TcpClient tc=newtcpclient(“localhost”,8080);//TCP客户端不是套接字。它封装了一个套接字。
字节[]缓冲区=新字节[4096];//使用4K作为网络缓冲区大小。
while(true)
{
使用(NetworkStream=tc.GetStream())
{
Int32读取;
while((read=stream.read(buffer,0,buffer.Length))!=0)
{
如果(读取%2!=0)
{
//TODO:处理16位值一半发送的情况。
持续
}
//每个数据包不太可能只包含2个字节,而是更可能一次发送16位整数序列,因此我们从缓冲区以2字节的步骤读取每个数据包:
对于(Int32 idx=0;idxUInt16值=(您好,您不需要
输入数据
顺便说一句。显然,您需要使用缓冲区类和writeUInt16xx…在节点端发送文本,并期望它可以作为int16读取,这并不奇怪。这并不能回答如何send@Selvin我还没有写完我的答案。谢谢!知道我的问题为什么被记下来了吗?
TcpClient tc = new TcpClient("localhost", 8080); // A TcpClient is not a Socket. It encapsulates a Socket.

Byte[] buffer = new Byte[4096]; // Use 4K as a network buffer size.
while (true)
{
    using( NetworkStream stream = tc.GetStream() )
    {
        Int32 read;
        while( ( read = stream.Read( buffer, 0, buffer.Length ) ) != 0 )
        {
            if( read % 2 != 0 )
            {
                // TODO: Handle the case where a 16-bit value is half-sent.
                continue;
            }
            
            // It is highly unlikely that each packet will contain only 2 bytes, instead it's more likely a sequence of 16-bit integers will be sent all-at-once, so we read each of them in 2-byte steps from the buffer:
            for( Int32 idx = 0; idx < read; idx += 2 )
            {
                Byte hi = buffer[ idx + 0 ];
                Byte lo = buffer[ idx + 1 ];

                UInt16 value = ( hi << 8 ) | ( lo );
                Debug.Log( value );
            }   
        } // while
    } // using
}


  [1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray