2016-07-05 28 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

相关问题