Как справиться с буферизацией данных, прочитанных из сети?
-
05-07-2019 - |
Вопрос
При чтении данных по сети вы указываете буфер для приема данных в:
byte[] b = new byte[4096];
socket.Receive(b);
Теперь моя первая мысль - это, конечно, повторно использовать приемный буфер, объявив его как переменную-член класса. Моя следующая проблема заключается в том, что я не получил все ожидаемые данные, поэтому мне нужно буферизовать свои данные. Это легко сделать, отслеживая количество полученных байтов и указав смещение:
socket.Receive(m_ReceiveBuffer, count, m_ReceiveBuffer.Length - count);
Теперь проблема в том, что если этого все еще недостаточно, я предполагаю, что мне нужно увеличить буфер, что означает копирование памяти, и продолжать получать в этот буфер. Если предположить, что что-то пошло не так, этот буфер продолжит расти, и, если будут получены достаточно большие сообщения, системе будет не хватать памяти.
Есть идеи, как правильно с этим справиться? Есть ли лучший способ получения данных, чем просто заполнение, копирование, увеличение, заполнение, копирование, увеличение, о котором я говорю?
Решение
читать частями:
const int ChunkSize = 4096;
int bytesRead;
byte[] buffer = new byte[ChunkSize];
while ((bytesRead = socket.Receive(buffer, 0, ChunkSize, SocketFlags.None)) > 0)
{
byte[] actualBytesRead = new byte[bytesRead];
Buffer.BlockCopy(buffer, 0, actualBytesRead, 0, bytesRead);
// Do something with actualBytesRead,
// maybe add it to a list or write it to a stream somewhere
}
Другие советы
Прежде чем начать с SYstem.Net.Sockets.Socket, вы уверены, что не можете использовать System.Net.Sockets.TcpClient (или UdpClient), который выполняет весь грязный буфер и превращает его в легко управляемый поток? р>
Если нет, помните, что объем данных, которые вы получаете, не должен быть равен тому, что вы запрашиваете, поэтому вы всегда должны смотреть на возвращаемое значение из функции recieve. И единственный способ не исчерпать память - это обработать то, что вы получили.
Сначала разделите код на получение данных и их обработку. Буфер приема должен хранить данные только до тех пор, пока код не получит возможность скопировать их в область обработки. В области обработки вы сможете определить, получили ли вы достаточно данных, чтобы сделать что-то полезное. Не оставляйте данные в буфере приема в сети, пока это не произойдет. Для сетевого приемного буфера, я думаю, использование кругового буфера поможет вам в вашей идее повторного использования буфера. Надеюсь, у вас есть представление о размерах сообщений. Это поможет в определении размера буфера. Если вы утверждаете (или что-то подобное), когда встречаются указатели чтения и записи циклического буфера, тогда увеличьте размер буфера. Как только размер буфера станет достаточно большим, вы сможете прочитать достаточно данных из буфера в код обработки со скоростью, достаточной для того, чтобы кольцевой буфер не переполнялся.