6

レンダリング アプリケーションに接続する C# クライアントを構築していますが、ひどく失敗します。この行に動作する python クライアントを分析することで、問題を絞り込みました。

def Startclient_Click(self, sender, e):
     try:
         s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
         s.connect((host, int(port)))
         message =  b'message "Render"'
         msg = struct.pack('<l',len(message))+struct.pack('<l',0)+message
         #print(msg)
         s.sendall(msg)
         data = s.recv(1024)

         data.decode("utf-8")
         self.datatxt.Text ="data: " +str(data)
         s.close()

         return
     except:
         self.datatxt.Text ="No Server Connection"
         return

C# では、これに相当するものは何ですか? 私の理解では、メッセージの前に 8 バイトが必要です。

4

1 に答える 1

3

struct.packは、フォーマットに従ってパックされる一連の値が続くフォーマットを取ります。あなたの質問では、次のように呼び出します。

struct.pack('<l', len(message))+struct.pack('<l',0)+message

これは、「このメッセージの長さをリトルエンディアン long としてパックし、その後にリトルエンディアン long としてパックされたゼロが続き、その後に残りのメッセージを追加する」と言っています。

C# でこの種の問題に取り組む場合、残念ながら struct.pack を直接移植することはできません。最も近いものは、次のような1回限りの変換にBitConverterを使用することです。

BitConverter.GetBytes((long)message.length) + BitConverter.GetBytes(0l) + message

またはBinaryWriterMemoryStreamに使用します。これにより、これらのツールを使用してエンディアンを制御できないという別の問題が発生します。それらは「IsLittleEndian」を公開するので、それらがどのように動作しているかはわかりますが、変更することはできません。

ただし、Jon Skeet はそのケースです。彼のMiscUtilsライブラリには、使用できる LittleEndianBitConverter (MiscUtil.Conversion.LittleEndianBitConverter)、または Writer/MemoryStream ルートを使用する場合の EndianBinaryWriter が含まれています。すべてをまとめると、MiscUtil ライブラリを参照し、次のようなものを使用します。

var bytes = new List<byte[]>(new[]
    {
        LittleEndianBitConverter.GetBytes(message.LongLength), 
        LittleEndianBitConverter.GetBytes(0l), 
        message
    });

var msg = new byte[bytes.Sum(barray => barray.LongLength)];
int offset = 0;
foreach (var bArray in bytes)
{
    System.Buffer.BlockCopy(bArray, 0, msg, offset, bArray.Length);
    offset = bArray.Length;
}

コードはテストされていませんが、妥当な出発点となるはずです。メッセージがすでにバイト配列であり、msg が返したい配列であると想定しています。プリミティブ型の最も効率的なコピー方法である System.Buffer.BlockCopy を使用します。

*編集*

質問の例を取り上げ、IDEOnePython コードとそれに相当する C#のクイック スクリプトをモックアップしました。ここでのキッカーは、Struct.Pack('<l', 0)呼び出しがバイトを無視し、それを出力に追加しないことです。これが、あなたをつまずかせている可能性があります。これにより、出力が 8 バイト長くなりすぎていました。

これらのスクリプトは、正しい方向を示しているはずです。それでも問題が解決しない場合は、試したコードを投稿できます。

参考までに、完成した Python のコードは次のとおりです。

import struct
message =  b'message "Render"'
msg = struct.pack('<l',len(message)) + struct.pack('<l',0) + message
print(":".join("{0:x}".format(ord(c)) for c in msg))

そしてC#では:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MiscUtil.Conversion;

public class Test
{
    public static void Main()
    {
        var message = Encoding.ASCII.GetBytes("message \"Render\"");

            var lenc = new LittleEndianBitConverter();

            var bytes = new List<byte[]>(new[]
            {
                lenc.GetBytes(message.LongLength),
                message
            });

            var msg = new byte[bytes.Sum(barray => barray.LongLength)];
            int offset = 0;
            foreach (var bArray in bytes)
            {
                Buffer.BlockCopy(bArray, 0, msg, offset, bArray.Length);
                offset = bArray.Length;
            }

            Console.WriteLine(BitConverter.ToString(msg).Replace("-", ":"));
    }
}
于 2013-10-13T10:47:01.983 に答える