отправить байт [] данных через сокет сетевого потока. c#

#c# #sockets #networkstream

#c# #сокеты #networkstream

Вопрос:

я хочу отправить строку json через networkstream . code на стороне клиента

  using (var ns = new NetworkStream(socket))
{
 string json = JsonConvert.SerializeObject(listCfile, Formatting.Indented);
 byte[] jsonbytes = Encoding.UTF8.GetBytes(json);
 byte[] jsonLength = BitConverter.GetBytes(jsonbytes.Length);
 ns.Write(jsonLength, 0, jsonLength.Length);
 ns.Write(jsonbytes, 0, jsonbytes.Length);
}
  

jsonbytes был байтом [988324]

На стороне сервера

  using (var ns = new NetworkStream(socket))
 {
 byte[] byDataLength = new byte[4];
ns.Read(byDataLength, 0, 4);
int jsonLength = BitConverter.ToInt32(byDataLength, 0);
byte[] byData = new byte[jsonLength];
ns.Read(byData, 0, jsonLength);
File.WriteAllBytes("E:\json.txt",byData);
}
  

byData был байтом [988324]

Но полученные мной байтовые данные не совпадают с отправленными мной jsonbytes.

мне нужна помощь.

Обновление! иногда это срабатывает. Полученные байтовые данные такие же, как jsonbytes, которые я отправлял несколько раз, это не работает : (

Комментарии:

1. «это приводит к потере некоторых данных» — не совсем подходящее описание проблемы. Пожалуйста, уточните.

2. Со стороны клиента отправляется ли длина JSON перед фактическими данными для создания буфера на стороне сервера для получения данных json?

3. @nura я думаю так же, как и вы, но я новичок в c # и кодировании, поэтому вы можете привести мне несколько примеров, большое спасибо.

4. Используете ли вы C # для обеих сторон? как насчет архитектуры? является ли клиент мобильным?

5. NetworkStream.Read : «Операция чтения считывает столько данных, сколько доступно, вплоть до количества байтов, указанного параметром size «. Вы игнорируете возвращаемое значение из, Read которое сообщает вам, сколько байтов было прочитано. Нет гарантии, что вызовы Write с одной стороны совпадают 1-1 с вызовами Read с другой стороны. TCP — это поток байтов. Не сообщения.

Ответ №1:

Вы можете попробовать использовать необработанные сокеты для отправки и получения, а также использовать поток памяти и механизм завершения пакета для данных неизвестной длины.

Ниже приведен фрагмент методов, демонстрирующих использование необработанных сокетов и буферизацию в потоке памяти до обнаружения конца пакета.

     protected const int SIZE_RECEIVE_BUFFER = 1024; /// Receive buffer size
    protected const string EOF = "!#~*|"; /// End of packet string
    MemoryStream _msPacket = new MemoryStream(); /// Memory stream holding buffered data packets
    int _delmtPtr = 0; /// Ranking pointer to check for EOF 
    Socket _baseSocket;
    public event EventHandler OnReceived;

    // TODO: -
    // Add methods to connect or accept connections.
    // When data is send to receiver, send with the same EOF defined above.
    //
    //
    public void RegisterToReceive()
    {
        byte[] ReceiveBuffer = new byte[SIZE_RECEIVE_BUFFER];
        _baseSocket.BeginReceive
        (
            ReceiveBuffer,
            0,
            ReceiveBuffer.Length,
            SocketFlags.None,
            new AsyncCallback(onReceiveData),
            ReceiveBuffer
        );
    }
    private void onReceiveData(IAsyncResult async)
    {
        try
        {
            byte[] buffer = (byte[])async.AsyncState;
            int bytesCtr = 0;
            try
            {
                if (_baseSocket != null)
                    bytesCtr = _baseSocket.EndReceive(async);
            }
            catch { }
            if (bytesCtr > 0)
                processReceivedData(buffer, bytesCtr);
            RegisterToReceive();
        }
        catch{ }
    }

    private void processReceivedData(byte[] buffer, int bufferLength)
    {
        byte[] eof = Encoding.UTF8.GetBytes(EOF);
        int packetStart = 0;
        for (int i = 0; i < bufferLength; i  )
        {
            if (buffer[i].Equals(eof[_delmtPtr]))
            {
                _delmtPtr  ;
                if (_delmtPtr == eof.Length)
                {
                    var lenToWrite = i - packetStart - (_delmtPtr - 1);
                    byte[] packet = new byte[lenToWrite   (int)_msPacket.Position];

                    if (lenToWrite > 0)
                        _msPacket.Write(buffer, packetStart, lenToWrite);

                    packetStart = i   1;
                    _msPacket.Position = 0;
                    _msPacket.Read(packet, 0, packet.Length);

                    try
                    {
                        if (OnReceived != null)
                            OnReceived(packet, EventArgs.Empty);
                    }
                    catch { }
                    _msPacket.Position = 0;
                    _delmtPtr = 0;
                }
            }
            else
            { _delmtPtr = 0; }
        }
        if (packetStart < bufferLength)
            _msPacket.Write(buffer, packetStart, bufferLength - packetStart);
        if (_msPacket.Position == 0)
            _msPacket.SetLength(0);
    }
  

Это позволяет получать данные большой длины и не зависит от длины отправителя.

Приведенные выше методы показывают, как получать только данные, поэтому придется включить другие методы для подключения, приема, отправки данных и т.д. На необработанных сокетах.

Комментарии:

1. большое вам спасибо, но для меня это так сложно. Есть другие способы сделать это. Длина моих данных не является неизвестной.