Как справиться с буферизацией данных, прочитанных из сети?

StackOverflow https://stackoverflow.com/questions/1403986

Вопрос

При чтении данных по сети вы указываете буфер для приема данных в:

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. И единственный способ не исчерпать память - это обработать то, что вы получили.

Сначала разделите код на получение данных и их обработку. Буфер приема должен хранить данные только до тех пор, пока код не получит возможность скопировать их в область обработки. В области обработки вы сможете определить, получили ли вы достаточно данных, чтобы сделать что-то полезное. Не оставляйте данные в буфере приема в сети, пока это не произойдет. Для сетевого приемного буфера, я думаю, использование кругового буфера поможет вам в вашей идее повторного использования буфера. Надеюсь, у вас есть представление о размерах сообщений. Это поможет в определении размера буфера. Если вы утверждаете (или что-то подобное), когда встречаются указатели чтения и записи циклического буфера, тогда увеличьте размер буфера. Как только размер буфера станет достаточно большим, вы сможете прочитать достаточно данных из буфера в код обработки со скоростью, достаточной для того, чтобы кольцевой буфер не переполнялся.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top