如何使用 Node 和 C# 通过 TCP 将简单的 UInt 发送到客户端
How to send a simple UInt over TCP to Client with Node and C#
我正在使用 Node 服务器向我在 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}`);
});
});
这是 Unity 中的 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);
}
}
}
我需要做一些重构,但一般来说,这可以通过 String
。通过 UInt16
无效。非常感谢任何帮助。
I would rather just pass the value as a UInt16 ... firstly, is this more efficient?
确实如此 - 但使用基于文本的协议而不是二进制协议有很多优点:即,调试和检查基于文本的协议比二进制协议容易得多。 HTTP 是基于文本的,例如 (HTTP/2 是 二进制协议,但这只是因为 Google 想要 超级优化 这在他们的规模上是有意义的,但对于绝大多数使用基于文本的协议的应用程序来说更有意义)。
and how do I do pass it and convert it on the client?
难度:
在 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.');
});
}
// [...]
});
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
我正在使用 Node 服务器向我在 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}`);
});
});
这是 Unity 中的 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);
}
}
}
我需要做一些重构,但一般来说,这可以通过 String
。通过 UInt16
无效。非常感谢任何帮助。
I would rather just pass the value as a UInt16 ... firstly, is this more efficient?
确实如此 - 但使用基于文本的协议而不是二进制协议有很多优点:即,调试和检查基于文本的协议比二进制协议容易得多。 HTTP 是基于文本的,例如 (HTTP/2 是 二进制协议,但这只是因为 Google 想要 超级优化 这在他们的规模上是有意义的,但对于绝大多数使用基于文本的协议的应用程序来说更有意义)。
and how do I do pass it and convert it on the client?
难度:
在 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.');
});
}
// [...]
});
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