2012-07-28 44 views
2

我有問題,我試圖以base64格式發送數據。來自客戶端的發送很好。但如果即時通訊嘗試在服務器上反編譯base64,即時通訊仍然總是出現錯誤,無效的base64文字記錄器。C#異步套接字:發送數據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); 
    } 
+0

只是想知道...爲什麼你要發送一個字符串作爲字符串=> Ascii => base64 => UTF8?這是否與特別期望base-64的API交談?如果沒有,你應該**只使用UTF8(其餘不需要)。這是否正在運行時,是否打算將「ASCII」替換爲「加密」?如果是這樣的話:那麼沒有理由使用base-64/UTF8步驟:只發送二進制文件 – 2012-07-28 07:21:01

+0

您收到的字節是否與您發送的字節匹配?特別要注意的是這是**不能保證**;您不會一直接收您發送的相同數據塊中的數據。您應該考慮一個「成幀」協議 - 最簡單的方法是,在每封郵件中裝入以下郵件中的字節數,以便接收方知道何時收到完整的郵件。 – 2012-07-28 07:24:30

+0

@MarcGravell他正在使用TCP和TCP保證可靠的字節流。這意味着他確實按照發送數據的順序接收數據。 – 2012-07-28 08:32:10

回答

1

正如馬克Gravell寫的,你不必要的網絡協議複雜化。網絡傳輸本質上是複雜的,所以避免任何不必要的複雜性!

當他說你必須確保你真的閱讀了所有發送的數據時,他也是絕對正確的。請看看那裏的文檔和示例(特別是Socket classSocket.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); 

另一個重要說明:BASE64與加密完全無關。它只是一種編碼,如UTF8或ASCII。如果您需要安全的通信通道,BASE64不是解決方案!如果竊聽者讀取BASE64編碼的消息,他可以輕鬆識別編碼,然後輕鬆解碼。

如果您需要安全通道,請使用強加密標準(如AES)或使用TLS等安全網絡協議(例如,通過HTTPS;使用HTTPS也可以解決由Marc Gravell提到的針對更復雜數據的「框架」問題交流)。

+0

非常感謝! :-)它很適合MSDN的例子。 ;-)收到數據的循環是問題.. – user1558672 2012-07-28 09:51:57