Клиент не получает никакого сообщения от сервера, потому что namedPipeClient.IsMessageComplete
должен вызываться после операции чтения. См. PipeStream.IsMessageComplete в документах:
Получает значение, указывающее, есть ли в сообщении больше данных
вернул из самой последней операции чтения .
В противном случае namedPipeClient.IsMessageComplete
возвращает true
, а код внутри while
-loop не выполняется. Таким образом, вам нужно переписать цикл while
в цикл do-while
, чтобы убедиться, что операция чтения происходит до тестирования namedPipeClient.IsMessageComplete
.
Но есть и другие проблемы, см. Комментарии для объяснений:
using (NamedPipeClientStream namedPipeClient = new NamedPipeClientStream(".", "test-pipe", PipeDirection.InOut))
{
namedPipeClient.Connect();
namedPipeClient.ReadMode = PipeTransmissionMode.Message;
// StringBuilder is more efficient for string concatenation
StringBuilder serverResponse = new StringBuilder();
byte[] readBytes = new byte[5];
do
{
// You need to store number of bytes read from pipe (to readCount variable).
// It can be less then the length of readBytes buffer, in which case
// GetString() would decode characters beyond end of message.
var readCount = namedPipeClient.Read(readBytes, 0, readBytes.Length);
var readText = Encoding.Default.GetString(readBytes, 0, readCount);
// You original code "overwrites" content of serverResponse variable instead
// of concatenating it to the previous value. So you would receive only
// the last part of the server message.
serverResponse.Append(readText);
// It is not needed to create new buffer, you can just reuse existing buffer
//readBytes = new byte[5];
// IsMessageComplete is now tested after read operation
} while (!namedPipeClient.IsMessageComplete);
System.Console.WriteLine(serverResponse.ToString());
// You current server implementation exits as soon as it sends message to the client
// and does not wait for incomming message. You'll have to change server accordingly
// to be able to send a message back to the server.
//byte[] writeBytes = Encoding.Default.GetBytes("Hello from client!\n");
//namedPipeClient.Write(writeBytes, 0, writeBytes.Length);
}
<Ч />
EDIT:
Когда именованный канал находится в режиме PipeTransmissionMode.Message
, каждый вызов NamedPipeServerStream.Write()
на сервере отправляет данные через канал в виде отдельного сообщения. Затем клиент может получать эти сообщения отдельно друг от друга
(в отличие от режима PipeTransmissionMode.Byte
, где клиент получает только один непрерывный поток байтов, независимо от того, сколько операций записи выполнял сервер, используя NamedPipeServerStream.Write()
).
Когда клиент читает данные из канала (namedPipeClient.Read()
), метод может вернуть меньше данных, чем запрошено (например, когда в буфере приема недостаточно места для хранения всего сообщения, или сообщение короче, чем запрошенный количество байтов), см. документы .
Возвращает общее количество байтов, которые считываются в буфер. Это
может быть меньше, чем количество запрошенных байтов , если это число
байты в данный момент недоступны, или 0, если конец потока
достиг.
Затем вы можете использовать namedPipeClient.IsMessageComplete
и readCount
, чтобы обнаружить это. Позвольте мне объяснить это на одном примере: представьте, что сервер отправляет клиенту сообщение ABCDEFGHIJKL
, закодированное в байтовый массив как { 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76 }
. Это сообщение имеет длину 12 байт, поэтому оно не помещается в ваш принимающий буфер (readBytes
) длиной 5 байт. Поэтому, когда клиент впервые читает из канала, используя namedPipeClient.Read()
, приемный буфер будет содержать только первые 5 байтов ({ 65, 66, 67, 68, 69 }
, соответствующих ABCDE
) сообщения. И здесь namedPipeClient.IsMessageComplete
поможет нам, потому что он вернет false
, указывая, что мы не получили полное сообщение, осталось еще несколько байтов, и мы должны продолжить чтение.
Второе чтение из канала будет аналогичным, мы прочтем вторую часть сообщения ({ 70, 71, 72, 73, 74 }
соответствует FGHIJ
), namedPipeClient.IsMessageComplete
по-прежнему false
, что указывает на неполное сообщение.
Когда третье чтение из канала завершится, будут прочитаны только 2 оставшихся байта ({ 75, 76 }
, соответствующих KL
), но наш буфер по-прежнему имеет длину 5 байтов, поэтому он будет выглядеть следующим образом: ({ 75, 76, 72, 73, 74 }
соответствует до KLHIJ
). Значения 72, 73, 74
все еще присутствуют в предыдущей итерации цикла. И теперь важно сохранить значение, возвращаемое из namedPipeClient.Read()
в переменную readCount
. Он будет содержать значение 2, указывающее, что допустимы только 2 байта буфера bytesRead
, а оставшиеся байты следует игнорировать.