2016-07-05 26 views
0

我和我的合作伙伴正在開發一個項目,在這個項目中我的合作伙伴正在使用Pascal進行開發,並使用Indy10套接字進行聯網,並且我正在使用C#在UWP項目中進行開發。因此,爲了聯網,我必須使用streamsocket命名空間。Indy10和System.Net.Sockets之間的網絡聯繫

問題是,我的合作伙伴使用帶有-1和false參數的ReadStream方法,這意味着接收流的長度是不確定的。因此,我必須從數據流中的數據(例如使用DataWriter類)發送計算的長度前綴(在這種情況下,我使用BitConverter.GetBytes方法)並繼續處理數據本身。 但Indy10套接字不收到任何東西。它看起來像在等待數據包,或者我不知道。

有沒有人遇到過這個問題?請幫助,我們一直在尋找解決方案大約兩週。我已經閱讀了StackOverflow中的所有類似問題,這是一篇關於使用幀,分隔符的博客。在Indy Socket源代碼本身中搜索解決方案。 請幫忙!

UPDATE 1
C#代碼。在這種情況下,我從WPF應用程序發送。邏輯,在UWP中流的使用方式幾乎相同,只是使用StreamSocket和DataWriter。

TcpClient client = new TcpClient(hostTextBox.Text, int.Parse(portTextBox.Text)); 

Byte[] byteMessage = Encoding.Unicode.GetBytes(messageTextBox.Text); 
Byte[] lenghtPrefix = BitConverter.GetBytes(byteMessage.Length); 
Byte[] concatedData = new byte[lenghtPrefix.Length + byteMessage.Length]; 
lenghtPrefix.CopyTo(concatedData, 0); 
byteMessage.CopyTo(concatedData, lenghtPrefix.Length); 

NetworkStream stream = client.GetStream(); 
StreamWriter writer = new StreamWriter(stream); 
writer.Write(concatedData); 
writer.Flush(); 

stream.Close(); 
client.Close(); 

但我們已經嘗試這種解決方案也:

Byte[] byteMessage = Encoding.Unicode.GetBytes(messageTextBox.Text); 
Byte[] lenghtPrefix = BitConverter.GetBytes(byteMessage.Length); 

Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp); 
socket.Connect(hostTextBox.Text, int.Parse(portTextBox.Text)); 

socket.Send(lenghtPrefix, SocketFlags.None); 
socket.SendBufferSize = byteMessage.Length; 
socket.Send(byteMessage, SocketFlags.None); 

socket.Close(); 

在服務器端Pascal代碼中,等待流。以這種方式接收是非常重要的,因爲軟件的其他模塊(也是使用Indy10在Pascal中編寫的)以這種方式與服務器進行通信。

function Receive(const AContext: TIdContext): string; 
var 
    Stream: TMemoryStream; 
begin 
    try 
    Result := ''; 
    Stream := TMemoryStream.Create; 
    if AContext.Connection.Connected then 
     AContext.Connection.IOHandler.ReadStream(Stream, -1, False); 
    finally 
    Result := UnPackStream(Stream); 
    Stream.Free; 
    end; 
end; 
+2

嘗試使用Wireshark嗅探數據包,看看如果您沒有發送正確或他沒有收到正確的消息。 – AlexDrenea

+0

我們不能根據對它做什麼以及如何表現的模糊描述來調試我們看不到的代碼。 –

+0

你在GitHub上試過了官方的[StreamSocket示例](https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/StreamSocket)嗎?此示例包含接收和發送功能。在發送數據時,它還會在內容之前將內容的長度寫爲UINT32的值。您可以使用此示例來確定問題出在您的客戶端還是服務器端。 –

回答

0

最後,這裏是解決方案。我們一整天都在努力。我們使用Synapse套接字作爲參考。最後這裏是UWP下的代碼,我們也在其他桌面項目(WPF,Winforms)中測試了它(使用TcpClientNetworkStream)。 BitConverter並且用一個數字前綴空洞流不起作用,因爲Indy等待二進制格式的長度,因此字節數組必須包含表示二進制長度的值。 我希望它能幫助有類似問題的人!

Windows.Networking.Sockets.StreamSocket socket = new Windows.Networking.Sockets.StreamSocket(); 
Windows.Networking.HostName serverHost = new Windows.Networking.HostName(hostTextBox.Text); 
string serverPort = portTextBox.Text; 
await socket.ConnectAsync(serverHost, serverPort); 

//Write data to the server. 
DataWriter writer = new DataWriter(socket.OutputStream); 

byte[] data = Encoding.Unicode.GetBytes(messageTextBox.Text); 
byte[] size = new byte[4]; 

ushort x = (ushort)(data.Length >> 16); 
ushort y = (ushort)(data.Length); 
size[0] = (byte)(x/256); 
size[1] = (byte)(x % 256); 
size[2] = (byte)(y/256); 
size[3] = (byte)(y % 256); 

writer.WriteBytes(size); 
writer.WriteBytes(data); 
await writer.StoreAsync(); 
await writer.FlushAsync(); 

writer.DetachStream(); 

//Read response. 
var bytes = new byte[4]; 

DataReader reader = new DataReader(socket.InputStream); 
await reader.LoadAsync(4); 

reader.ReadBytes(bytes); 
int length = bytes[0] * 256 * 256 * 256 + bytes[1] * 256 * 256 + bytes[2] * 256 + bytes[3]; 

byte[] dat = new byte[length]; 
var count = await reader.LoadAsync((uint)length); 
reader.ReadBytes(dat); 

responseTextBlock.Text = Encoding.Unicode.GetString(dat); 

reader.DetachStream(); 
socket.Dispose(); 
0

當調用在印TIdIOHandler.ReadStream(),如果AByteCount是-1和AReadUntilDisconnect爲False,ReadStream()將讀取的前4個字節(的Int32)或8個字節(的Int64)(取決於TIdIOHandler.LargeStream屬性的值),並將它們解釋爲網絡字節順序的整數(big-endian),然後讀取由該整數指定的字節數(如果大於0)。

您的第一個C#示例的主要問題是您使用的是StreamWriter,它被設計用於發送文本,而不是二進制數據。如果您嘗試使用StreamWriter編寫Byte[]陣列,它將不會按原樣發送,它將被格式化爲與Indy不兼容的文本表示。您不需要StreamWriter,您可以按原樣使用NetworkStream,它具有用於Byte[]數據的Write()方法。或使用BinaryWriter

這兩個C#示例的另一個問題是,您正在使用BitConverter而沒有考慮端。它的GetBytes(Int32)方法創建一個與調用機器的體系結構相同的endian字節數組。 Windows主要是一個小端環境,但ReadStream()期望big-endian中的整數字節。

嘗試更多的東西是這樣的:

TcpClient client = new TcpClient(hostTextBox.Text, int.Parse(portTextBox.Text)); 

Byte[] byteMessage = Encoding.Unicode.GetBytes(messageTextBox.Text); 
Byte[] lengthPrefix = BitConverter.GetBytes(byteMessage.Length); 
if (BitConverter.IsLittleEndian) 
    Array.Reverse(lengthPrefix); 

NetworkStream stream = client.GetStream(); 
stream.Write(lengthPrefix, 0, lengthPrefix.Length); 
stream.Write(byteMessage, 0, byteMessage.Length); 

stream.Close(); 
client.Close(); 

或者這樣:

TcpClient client = new TcpClient(hostTextBox.Text, int.Parse(portTextBox.Text)); 

Byte[] byteMessage = Encoding.Unicode.GetBytes(messageTextBox.Text); 
Byte[] lengthPrefix = BitConverter.GetBytes(byteMessage.Length); 
if (BitConverter.IsLittleEndian) 
    Array.Reverse(lengthPrefix); 

NetworkStream stream = client.GetStream(); 
BinaryWriter writer = new BinaryWriter(stream); 

// BinaryWriter.Write(Int32) writes in little-endian only, 
// so you still need to use Write(Byte[]) for the length value... 
writer.Write(lengthPrefix); 
writer.Write(byteMessage) 
writer.Flush(); 

stream.Close(); 
client.Close(); 
+0

你是真的,使用StreamWriter有時會發送凌亂的數據。無論如何,我沒有嘗試顛倒長度前綴數組。我會試一試。我非常感謝你的幫助! – DigheadsFerke

相關問題