NetworkStream. Запишите возвраты сразу - как я могу сказать, когда это закончило отправлять данные?

Исключение нулевого указателя - это индикатор того, что вы используете объект, не инициализируя его.

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

public class Student {

    private int id;

    public int getId() {
        return this.id;
    }

    public setId(int newId) {
        this.id = newId;
    }
}

Приведенный ниже код дает вам исключение с нулевым указателем.

public class School {

    Student obj_Student;

    public School() {
        try {
            obj_Student.getId();
        }
        catch(Exception e) {
            System.out.println("Null Pointer ");
        }
    }
}

Поскольку вы используете Obj_Student, но вы забыли инициализировать его, как в правильном коде, показанном ниже:

public class School {

    Student obj_Student;

    public School() {
        try {
            obj_Student = new Student();
            obj_Student.setId(12);
            obj_Student.getId();
        }
        catch(Exception e) {
            System.out.println("Null Pointer ");
        }
    }
}
9
задан dan gibson 16 September 2008 в 00:14
поделиться

9 ответов

Я не программист C#, но способ, которым Вы задали этот вопрос, является немного вводящим в заблуждение. Единственный способ знать, когда Ваши данные были "получены" для любого полезного определения "полученных", состоит в том, чтобы иметь определенное сообщение подтверждения в Вашем протоколе, который указывает, что данные были полностью обработаны.

Данные не "оставляют" Вашу сетевую плату, точно. Лучший способ думать об отношениях Вашей программы к сети:

Ваша программа-> много запутывающего материала-> программа однорангового узла

Список вещей, которые могли бы быть в "большом количестве запутывающего материала":

  • CLR
  • ядро операционной системы
  • виртуализированный сетевой интерфейс
  • переключатель
  • программный брандмауэр
  • аппаратный брандмауэр
  • маршрутизатор, выполняющий преобразование сетевых адресов
  • маршрутизатор на конце коллеги, выполняющем преобразование сетевых адресов

Так, если Вы находитесь на виртуальной машине, которая размещается под другой операционной системой, которая имеет программный брандмауэр, который управляет сетевым поведением виртуальной машины - когда данные "действительно" оставили Вашу сетевую плату? Даже в лучшем варианте развития событий, многие из этих компонентов могут отбросить пакет, который должна будет ретранслировать Ваша сетевая плата. Это "Оставило" Вашу сетевую плату, когда первая (неудачная) была предпринята попытка? Самые сетевые API сказали бы "нет", это не было "отправлено", пока другой конец не отправил подтверждение TCP.

Тем не менее документация для NetworkStream. Запись, кажется, указывает, что не возвратится, пока она, по крайней мере, не инициировала 'отправить' операцию:

Блоки Метода записи до требуемого числа байтов отправляются, или SocketException брошен.

Конечно, "отправляется", несколько неопределенно по причинам, которые я привел выше. Существует также возможность, что данные будут "действительно" отправлены Вашей программой и получены программой однорангового узла, но одноранговый узел разрушит или иначе не на самом деле обработает данные. Таким образом, необходимо сделать a Write сопровождаемый a Read из сообщения, которое будет только испускаться Вашей коллегой, когда оно на самом деле обработает сообщение.

11
ответ дан 4 December 2019 в 10:34
поделиться

В целом я рекомендовал бы отправить подтверждение от клиента так или иначе. Тем путем можно быть на 100% уверены, что данные были получены и получены правильно.

2
ответ дан 4 December 2019 в 10:34
поделиться

TCP является "надежным" протоколом, что означает, что данные будут получены в другом конце, если не будет никаких ошибок сокета. Я видел многочисленные усилия при пересмотре TCP с высокоуровневым подтверждением приложения, но по моему скромному мнению это обычно - пустая трата времени и пропускная способность.

Обычно проблема, которую Вы описываете, решена посредством нормального клиент-серверного дизайна, который в его самой простой форме идет как это...

Клиент отправляет запрос к серверу и делает чтение блокирования на сокете, ожидающем некоторого ответа. Если будет проблема с соединением TCP затем это, то чтение прервется. Клиент должен также использовать тайм-аут для обнаружения любой связанной с несетью проблемы с сервером. Если запрос перестал работать или испытывает таймаут затем, клиент может повторить, сообщить об ошибке и т.д.

После того как сервер обработал запрос и отправил ответ, он обычно больше не заботится о том, что происходит - даже если сокет уходит во время транзакции - потому что это до клиента для инициирования дальнейшего взаимодействия. Лично, я нахожу очень утешительным быть сервером.:-)

5
ответ дан 4 December 2019 в 10:34
поделиться

Если я должен был предположить, NetworkStream полагает, что данные отправляются, после того как он передает буфер к Windows Socket. Так, я не уверен, что существует способ выполнить то, что Вы хотите через TcpClient.

1
ответ дан 4 December 2019 в 10:34
поделиться

Я не могу думать о сценарии где NetworkStream. Запись не отправила бы данные на сервер как можно скорее. Запрещая серьезную перегрузку сети или разъединение, это должно закончиться на другом конце в течение разумного срока. Действительно ли возможно, что у Вас есть проблема протокола? Например, с HTTP заголовки запроса должны закончиться пустой строкой, и сервер не отправит ответа, пока каждый не произойдет - делает используемый протокол, имеют подобную характеристику конца сообщения?

Вот некоторый более чистый код, чем Ваша исходная версия, удаляя делегата, поле и Поток. Сон. Это формует тот же самый путь функционально.

void SendData(TcpClient tcp, byte[] data) {
    NetworkStream ns = tcp.GetStream();
    // BUG?: should bytWriteBuffer == data?
    IAsyncResult r = ns.BeginWrite(bytWriteBuffer, 0, data.Length, null, null);
    r.AsyncWaitHandle.WaitOne();
    ns.EndWrite(r);
}

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

1
ответ дан 4 December 2019 в 10:34
поделиться

Как насчет того, чтобы использовать Сброс () метод.

ns.Flush()

Это должно гарантировать, что данные записаны перед продолжением.

0
ответ дан 4 December 2019 в 10:34
поделиться

Я пытаюсь понять намерение.NET разработчики NetworkStream, и они должны разработать его этот путь. После Записи данные для больше отправки не обрабатываются.NET. Поэтому разумно, что Запись сразу возвращается (и данные будут отправлены из NIC скоро).

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

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

1
ответ дан 4 December 2019 в 10:34
поделиться

Возможно, попытайтесь установить tcp.NoDelay = true

-1
ответ дан 4 December 2019 в 10:34
поделиться

.NET рева является сокетами окон, которые используют TCP. TCP использует пакеты ACK для уведомления отправителя, что данные были переданы успешно. Таким образом, машина отправителя знает, когда данные были переданы, но нет никакого пути (что я знаю) получить ту информацию в .NET.

править: Просто идея, которую никогда пробуют: Запишите () блоки, только если буфер сокетов полон. Таким образом, если мы понижаемся, который буферизует размер (SendBufferSize) к очень низкой стоимости (8? 1? 0?) мы можем получить то, что мы хотим :)

0
ответ дан 4 December 2019 в 10:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: