3

データをbase64形式で送信しようとしているという問題があります。クライアントからの送信はうまく機能します。しかし、サーバーでbase64を逆コンパイルしようとすると、常にエラーが発生し、base64文字が無効になります。

安全な転送のために、クライアントからサーバーへのデータを暗号化し、サーバー上で復号化する方法を探しています。

私のコードは次のようなATMを示しています:クライアント:

socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.BeginConnect(ipAddress, ipAddressPort, new AsyncCallback(testA), null);

protected static void testA (IAsyncResult ar) {
      socket.EndConnect(ar);
      string str = EncodeTo64("Hello world!");
      socket.BeginSend(System.Text.Encoding.UTF8.GetBytes(str), 0, str.Length, SocketFlags.None, new AsyncCallback(testB), socket);
    }
    protected static void testB (IAsyncResult ar) {
      socket.EndSend(ar);
      socket.BeginReceive(bytes, 0, bytes.Length, SocketFlags.None, new AsyncCallback(testC), socket);
    }
    protected static void testC (IAsyncResult ar) {
      socket.EndReceive(ar);
      MessageBox.Show(System.Text.Encoding.UTF8.GetString(bytes));
    }
    static public string EncodeTo64(string toEncode)
    {
      byte[] toEncodeAsBytes
            = System.Text.ASCIIEncoding.ASCII.GetBytes(toEncode);
      string returnValue
            = System.Convert.ToBase64String(toEncodeAsBytes);
      return returnValue;
    }
    static public string DecodeFrom64(string encodedData)
    {
      byte[] encodedDataAsBytes
          = System.Convert.FromBase64String(encodedData);
      string returnValue =
         System.Text.ASCIIEncoding.ASCII.GetString(encodedDataAsBytes);
      return returnValue;
    }

サーバ:

serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, 4444);

serverSocket.Bind(ipEndPoint);
serverSocket.Listen(4);


serverSocket.BeginAccept(new AsyncCallback(OnAccept), null);

 protected static byte[] byteData = new byte[1024];
private void OnAccept(IAsyncResult ar)
    {
      Socket clientSocket = serverSocket.EndAccept(ar);

      //Start listening for more clients
      serverSocket.BeginAccept(new AsyncCallback(OnAccept), null);

      //Once the client connects then start receiving the commands from her
      // Create the state object.
      clientSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None,
           new AsyncCallback(OnReceive), clientSocket);
    }

private void OnReceive(IAsyncResult ar) {
      Socket clientSocket = (Socket)ar.AsyncState;
      clientSocket.EndReceive(ar);
MessageBox.Show(DecodeFrom64(System.Text.Encoding.UTF8.GetString(byteData)));
}
    static public string EncodeTo64(string toEncode)
    {
      byte[] toEncodeAsBytes
            = System.Text.ASCIIEncoding.ASCII.GetBytes(toEncode);
      string returnValue
            = System.Convert.ToBase64String(toEncodeAsBytes);
      return returnValue;
    }
    static public string DecodeFrom64(string encodedData)
    {
      byte[] encodedDataAsBytes
          = System.Convert.FromBase64String(encodedData);
      string returnValue =
         System.Text.ASCIIEncoding.ASCII.GetString(encodedDataAsBytes);
      return returnValue;
    }
    public void OnSend(IAsyncResult ar) {
      Socket client = (Socket)ar.AsyncState;
      client.EndSend(ar);
    }
4

1 に答える 1

2

Marc Gravellが書いたように、ネットワークプロトコルを不必要に複雑にします。ネットワーク送信は本質的に複雑なので、不必要な複雑さは避けてください。

また、送信されたすべてのデータを実際に読み取ることを確認する必要があると彼が言ったときも、彼は絶対に正しいです。ドキュメントとそこにある例(特にSocketクラスSocket.EndReceive ;を呼び出すだけであることに注意してください)をご覧ください。EndReceiveすべてが読み取られたことを確認するには不十分です)。主なポイントは次のとおりです。すべての送信データが読み取られたことを確認するサーバー側のループが必要です。送信するデータが単純で、ネットワークの信頼性が非常に高い場合(ケーブル経由のローカルイーサネット、WiFiなし、インターネット、特にモバイルインターネットは信頼性が低い)、データが到着しなくなるまでループするだけで十分な場合があります。より複雑なシナリオでは、Marcが提案したようにフレーミングプロトコルを使用する方が賢明です。これにより、読み取りループをいつ終了するかを決定するためのより信頼性の高い方法が提供されます。

次のコードを使用すると、エラーを簡単に再現できます。

var data = Encoding.ASCII.GetBytes("Hello World!");
var base64 = Convert.ToBase64String(data);
var bytesToSend = Encoding.UTF8.GetBytes(base64);
var stringRecieved = Encoding.UTF8.GetString(bytesToSend).Substring(0, 5);
var decoded = Convert.FromBase64String(stringRecieved);
var result = Encoding.ASCII.GetString(decoded);
Console.WriteLine("{0} -> {1} -> {2}", base64, stringRecieved, result);

.Substring(0, 5)、完全に読み取られていないネットワークストリームをシミュレートします。削除すると.Substring、すべてが正常に機能します。Marcsポイントをサポートするには、データを送信するには次の方法で十分です。

var bytesToSend = Encoding.UTF8.GetBytes("Hello World!");
var stringRecieved = Encoding.UTF8.GetString(bytesToSend);

もう1つの重要な注意:BASE64は暗号化とはまったく関係がありません。これは、UTF8やASCIIのような単なるエンコーディングです。安全な通信チャネルが必要な場合、BASE64は解決策ではありません。盗聴者がBASE64でエンコードされたメッセージを読み取った場合、盗聴者はエンコードを簡単に識別し、それをデコードするのは簡単です。

安全なチャネルが必要な場合は、AESなどの強力な暗号化標準を使用するか、TLSなどの安全なネットワークプロトコルを使用します(たとえば、HTTPS経由。HTTPSを使用すると、Marc Gravellがより複雑なデータ交換で言及した「フレーミング」問題も解決できる場合があります)。

于 2012-07-28T09:10:17.917 に答える