这就是场景:我正在建立TCP连接(对自己)以字符串格式发送一些数据。我创建一个连接,我发送数据,我立即关闭连接(我不想同步等待数据)。在发送字符串之前,我将其长度(data.Length
)附加到字符串的前面,因此我知道在接收字符串时要读取多少数据。
我有StreamSocketListener
监听来自TCP连接的传入数据,我为外界制作了一些" helper" -class来简化内容。该类被实例化一次,并调用方法Start
以开始侦听连接。这就是场景。
当我发送数据(对我自己,但这不重要)时,我在方法System.OutOfMemoryException
中得到StreamReadLine
。
对我而言,为什么会发生这种情况并不是很明显,所以这就是我在这里的原因。我希望有人之前已经解决了这个问题并且知道问题是什么。
public delegate void TCPRequestHandler(string data, string sender);
public class TCPSocketListener
{
private int port;
private StreamSocketListener listener;
private bool mIsActive = false;
private event TCPRequestHandler requestHandlerCallback;
public bool isActive
{
get { return mIsActive; }
}
public TCPSocketListener(int port, TCPRequestHandler requestHandlerCallback)
{
this.port = port;
this.requestHandlerCallback = requestHandlerCallback;
}
public async void Start()
{
if (!mIsActive)
{
mIsActive = true;
listener = new StreamSocketListener();
listener.Control.QualityOfService = SocketQualityOfService.Normal;
listener.ConnectionReceived += Listener_ConnectionReceived;
await listener.BindServiceNameAsync(port.ToString());
}
}
public void Stop()
{
if (mIsActive)
{
listener.Dispose();
mIsActive = false;
}
}
async void Listener_ConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
{
string data = await ExtractRequestData(args.Socket);
await Task.Run(() => requestHandlerCallback(data, args.Socket.Information.RemoteHostName.CanonicalName));
}
private async Task<string> ExtractRequestData(StreamSocket socket)
{
//Initialize IO classes
DataReader reader = new DataReader(socket.InputStream);
//DataWriter writer = new DataWriter(socket.OutputStream);
//writer.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
// get the data on the stream
string data = await StreamReadLine(reader);
socket.Dispose();
return data;
}
private static async Task<string> StreamReadLine(DataReader reader)
{
System.Diagnostics.Debug.WriteLine("reading data");
var stringHeader = await reader.LoadAsync(4);
if (stringHeader == 0)
{
System.Diagnostics.Debug.WriteLine("Header of the data was 0, for whatever reason");
return "null";
}
int strLength = reader.ReadInt32();
uint numStrBytes = await reader.LoadAsync((uint)strLength);
string data = reader.ReadString(numStrBytes);
System.Diagnostics.Debug.WriteLine("read " + data);
return data;
}
}
答案 0 :(得分:2)
感谢Lasse和Stephen(对问题的评论),因为他们是对的。数据长度确实首先以数据为前缀,然后作为字节复制,而不是先将文本作为字节,然后将长度作为字节加前缀。
所以我所做的是创建一个总长度(有效载荷)的新字节数组,然后获取数据的字节,然后用数据长度填充前4个字节。像这样:
转让前:
// Add the length of the data at the start, so we know how much characters to read when receiving this
Int32 dataLength = data.Length;
// Add the data to be sent into the buffer
byte[] payload = new byte[sizeof(Int32) + (dataLength * sizeof(char))];
byte[] dataBytes = System.Text.Encoding.UTF8.GetBytes(data);
System.Buffer.BlockCopy(dataBytes, 0, payload, 4, dataBytes.Length);
payload[0] = (byte)(dataLength >> 24);
payload[1] = (byte)(dataLength >> 16);
payload[2] = (byte)(dataLength >> 8);
payload[3] = (byte)dataLength;
收到时:
var stringHeader = await reader.LoadAsync(4);
Int32 strLength = reader.ReadInt32();
uint numStrBytes = await reader.LoadAsync((uint)strLength);
string data = reader.ReadString(numStrBytes);