2016-10-12 21 views
2

我對C#編程相當陌生,通常處理PLC編程和HMI/SCADA系統開發。最後一個只涉及一點C/VBS腳本。C#將對象類型轉換爲byte [],通過TCP發送並轉換回雙重

最近,在我的一個項目中,我將最初在LabVIEW中開發的SCADA系統升級/遷移到西門子WinCC應用程序。 在LabVIEW項目中,有一部分負責通過TCP套接字將標籤值(與標籤名稱捆綁在一起並轉換爲字符串的值)發送到運行C#應用程序(TCP客戶端)的另一臺PC,該應用程序正在接收字節數組並將其轉換增值一倍。

LabVIEW TCP Server Example

與另一臺PC上運行的TCP客戶端的代碼的一部分。

TcpClient     _client; 
NetworkStream    _stream = null; 
byte[]      _data = new byte[8192]; 

{...} 
try 
{ 
    _client  = new TcpClient(properties.IpAddress, properties.Port); 
} 
{...} 
    try 
    { 
     _stream  = _client.GetStream(); 
{...} 
     int NumBytesInRecvBuffer = _stream.Read(_data, 0, 8192); 

{...} 
      if(_data[3] == paramCount) 
      { 
       for(int i = 0; i < paramCount; i++) 
       { 
        double Value = MakeDouble(_data, 4+(i*8)); 
        fmacsParams[i].NumericalValue = Value; 
       } 
      } 
    } 

MakeDouble()函數在TCP客戶端。

private unsafe double MakeDouble(byte[] data, int StartIndex) 
{ 
    double result; 
    byte* b = (byte*)&result; 
    b[0] = data[StartIndex + 7]; 
    b[1] = data[StartIndex + 6]; 
    b[2] = data[StartIndex + 5]; 
    b[3] = data[StartIndex + 4]; 
    b[4] = data[StartIndex + 3]; 
    b[5] = data[StartIndex + 2]; 
    b[6] = data[StartIndex + 1]; 
    b[7] = data[StartIndex + 0]; 
    return(result);   
} 

我設法開發在C#簡單的應用程序,它是一個TCP偵聽和讀取從WinCC運行標籤值作爲對象

object ft107Flow = oType.InvokeMember("GetValue", System.Reflection.BindingFlags.InvokeMethod, null, wincc, new object[] { "FT107_Flow" }); 

然後將其轉換爲double和字節數組。最後,數組中的所有字節都與函數SwapBytes()交換並放入數據數組,以便它可以通過TCP發送爲字節數組。

{...} 
const int paramCount = 30; 
double[] WinCC_Tags = new double[paramCount]; 

WinCC_Tags[0] = Convert.ToDouble(ft107Flow); 
{...} 
byte[] data = new byte[4 + paramCount * 8]; 
Array.Clear(data, 0, data.Length); 

byte[] UnswappedByte; 
byte[] SwappedByte; 

data[3] = paramCount; 

for (int i = 0; i < paramCount; i++) 
{ 
    int j; 

    UnswappedByte = BitConverter.GetBytes(WinCC_Tags[i]); 
    SwappedByte = SwapBytes(UnswappedByte, 0); 

    j = (4 + i * 8); 

    data[j] = SwappedByte[0]; 
    data[j + 1] = SwappedByte[1]; 
    data[j + 2] = SwappedByte[2]; 
    data[j + 3] = SwappedByte[3]; 
    data[j + 4] = SwappedByte[4]; 
    data[j + 5] = SwappedByte[5]; 
    data[j + 6] = SwappedByte[6]; 
    data[j + 7] = SwappedByte[7]; 
} 

我現在面臨的問題是客戶收到的這些值是不一樣的。由於這種雙重或三重轉換(對象 - >雙精度,雙精度 - >字節數組;字節數組 - >雙精度),精度似乎丟失了。

例如,在WinCC運行系統中,變量值爲15.3。當它轉換爲雙倍時,它等於15.300000190734863。然後data[12..19] = {0x40, 0x2e, 0x99, 0x99, 0xA0, 0x00, 0x00, 0x00}。看起來

由客戶機接收到的數據如下:

_data[12..19] = {0x40, 0x2e, 0x99, 0x99, 0xA0, 0x00, 0x00, 0x00}

Value = 15.001172065734863

它看起來像由客戶端接收相同的數據(字節陣列),但是轉換不等於後的值到WinCC運行系統中的值。

請確認是否有修改TCP偵聽器端的方法,以便TCP客戶端在使用MakeDouble()函數進行轉換並且不觸及TCP客戶端代碼(不允許修改它)的情況下接收正確的數據。

+0

簡單:字節[]數據=新的字節[] {0x40的,器0x2E,0x99,0x99,0XA0,0x00時,0×00,0×00}; double number = BitConverter.ToDouble(data.Reverse()。ToArray(),0);我得到15.300。 – jdweng

+0

他使'MakeDouble()'功能正常工作 –

回答

1

而不是自己交換字節我建議您使用 this包。這是一個BigEdian BinaryReader在/作家

你可以使用這樣的

using (MemoryStream stream = new MemoryStream()) 
using (BeBinaryReader BeReader = new BeBinaryReader(stream)) 
{ 
    stream.Position = 3; 
    if(BeReader.ReadByte() == paramCount) 
    for (int i = 0; i < paramCount; i++) 
    { 
     double Value = BeReader.ReadDouble(); 
     fmacsParams[i].NumericalValue = Value; 
    } 
} 
+0

事情是我不允許修改TCP客戶端代碼。 – matmix1

+0

但是對於讀寫數據服務器端你可以使用BigEdian BinaryReader/Writer –

+0

有沒有什麼辦法來證明函數MakeDouble()裏面有什麼,將字節數組轉換成double,這樣就會失去精度結果它會返回稍微不同的值? – matmix1

0

我不是超級熟悉C#如何處理不安全代碼和指針,但是如果我從C的角度回答這個問題,它看起來像第6個字節被某些東西覆蓋。

15.300000190734863和15.0011720657349之間的區別是 {0x00時,0×00,0×00,0XA0,0x99,0x99,0x2E之間,0x40的}和{0x00時,0×00,0×00,0XA0,0x99,爲0x00,0x2E之間,0x40的}。

嘗試使用以下代碼

private double MakeDouble(byte[] data, int StartIndex) 
    { 
     double result; 
     byte[] b = new byte[8]; 
     b[0] = data[StartIndex + 7]; 
     b[1] = data[StartIndex + 6]; 
     b[2] = data[StartIndex + 5]; 
     b[3] = data[StartIndex + 4]; 
     b[4] = data[StartIndex + 3]; 
     b[5] = data[StartIndex + 2]; 
     b[6] = data[StartIndex + 1]; 
     b[7] = data[StartIndex + 0]; 
     result = BitConverter.ToDouble(b, 0); 
     return (result); 
    } 
+0

但是,如果在兩臺不同的PC上使用相同的軟件編譯相同的代碼,實際上會導致不同的結果? – matmix1

+0

一般來說(不是C#專用),具有不同的編譯器或CLR版本和/或設置會導致不同的輸出,因爲系統可以嘗試以不同的方式對其進行優化。在C代碼中,如果代碼不符合正確的編碼標準,優化器可能會導致您的代碼無法預料地執行,即使以非優化方式進行編譯時它會按預期執行;我只是提到這個例子。 2個問題: a)你有沒有試過運行上面的代碼? b)您是否嘗試過在一臺機器上構建並在另一臺機器上運行構建? – bizziedog

相關問題