Я отвечу на третью часть вашего вопроса более подробно.
Документация MSDN гласит:
Когда ваше приложение вызывает BeginWrite, система использует отдельный поток для выполнения указанного метода обратного вызова и блокирует EndWrite до тех пор, пока NetworkStream не отправит запрошенное количество байтов или не выдаст исключение.
Насколько я понимаю, будет ли метод обратного вызова вызываться сразу после вызова BeginSend, зависит от базовой реализации и платформы. Например, если порты завершения ввода-вывода доступны в Windows, этого не будет. Поток из пула потоков будет заблокирован перед вызовом.
Фактически, метод BeginWrite от NetworkStream просто вызывает метод BeginSend базового сокета в моей реализации .Net. Мой использует основную функцию WSASend Winsock с портами завершения, где это возможно. Это делает его гораздо более эффективным, чем просто создание собственного потока для каждой операции отправки / записи, даже если вы должны использовать пул потоков.
Затем метод Socket.BeginSend вызывает метод OverlappedAsyncResult.CheckAsyncCallOverlappedResult, если результатом WSASend был IOPending, который, в свою очередь, вызывает собственную RegisterWaitForSingleObject функцию Win32. Это приведет к тому, что один из потоков в пуле потоков будет блокироваться до тех пор, пока метод WSASend не сообщит о своем завершении, после чего вызывается метод обратного вызова.
Метод Socket.EndSend, вызываемый NetworkStream.EndSend, будет ожидать завершения операции отправки. Причина этого заключается в том, что если порты завершения ввода-вывода недоступны, метод обратного вызова будет вызван сразу.
Я должен еще раз подчеркнуть, что эти детали относятся к моей реализации .Net и моей платформы, но, надеюсь, это даст вам некоторое представление.