Getting rare exceptions when trying to send a string through pipe - c#

I have two different applications communicating with pipes. Most requests work fine, but from time to time, I get following exception when trying to send a string through pipe:
System.InvalidOperationException : Pipe hasn't been connected yet.
With the following stack:
at System.IO.Pipes.PipeStream.CheckWriteOperations()
at System.IO.Pipes.PipeStream.Flush()
at System.IO.StreamWriter.Flush(Boolean flushStream, Boolean flushEncoder)
at System.IO.StreamWriter.Dispose(Boolean disposing)
at System.IO.TextWriter.Dispose()
Last line points to the line in client pipe code, I marked it with ">"
using (var pipeClient =
new NamedPipeClientStream("PipeName"))
{
try
{
using (var streamWriter = new StreamWriter(pipeClient))
{
pipeClient.Connect(20000);
streamWriter.AutoFlush = true;
streamWriter.WriteLine(dataToSend);
pipeClient.WaitForPipeDrain();
>}
}
catch (Exception x)
{
Log.Error("ExceptionText");
}
}
On server, this is how pipes are being handled:
using (var streamReader = new StreamReader(pipeServer))
{
pipeServer.WaitForConnection();
string data;
while ((data = streamReader.ReadLine()) != null)
{
//Process the data here...
}
pipeServer.Disconnect();
}
According to MSDN, PipeStream.Flush() isn't even supposed to do anything, yet it somehow fails? I'm confused about the whole situation.
What does it all mean? Does it try to dispose the pipe that somehow became disconnected in process?
If yes, what can I do about it?
Or am I doing something wrong?
Edit:
According to reference, during PipeStream.Flush() pipe state is checked. If state happens to be WaitingToConnect, it returns the exception I'm getting.
How can this happen though? If pipeClient.Connect(20000); happened without exceptions, then the state has to be different, whether it is Connected, Broken or something else.

Related

Why do Pipes Hang When I try to Read Them?

I am making a program that starts a child process and communicates via anonymous pipes. When I read from a pipe, the program hangs at the first ReadLine() call as seen in the following code method:
// Reads messages sent from module's process via anonymous pipe
internal string[] ReadPipe() {
try {
Log.Verbose("Checking read pipe");
// Check for sync message and return null if there is no message to receive
string pipeMessage = _pipeInReader.ReadLine(); // HANGS ON THIS LINE
if(pipeMessage == null || !pipeMessage.StartsWith("SYNC")) {
Log.Verbose("No message found in pipe");
return null;
}
// Return array of message lines
Log.Verbose("Received message from module {ModuleName}", _fileInfo.Name);
List<string> pipeMessageLines = new();
do {
pipeMessage = _pipeInReader.ReadLine();
pipeMessageLines.Add(pipeMessage);
Log.Debug(pipeMessage);
} while(pipeMessage != null && !pipeMessage.StartsWith("END"));
return pipeMessageLines.ToArray();
} catch(Exception e) {
Log.Error(e.ToString());
return null;
}
}
The code I am using to write to the pipe is the following:
// Sends a message to module's process via anonymous pipe
public static void WritePipe(string message) {
try {
Log.Verbose("Sending \"{Message}\" to kit pipe", message);
// Send sync message and wait for module process to receive it
Log.Verbose("Waiting for pipe drain");
_pipeOutWriter.Write("SYNC");
_pipeOut.WaitForPipeDrain();
// Send the specified message
Log.Verbose("Pipe drained. Sending message");
_pipeOutWriter.Write(message);
_pipeOutWriter.Write("END");
} catch(Exception e) {
Log.Error(e.ToString());
}
}
Why does it hang at that ReadLine() line?
Thanks in advance!
Without a proper minimal, reproducible example, it's impossible to say for sure. However, one glaring problem with your code is that when you write to the _pipeOutWriter object, you don't call Flush(). Assuming that's a TextWriter, by default it's going to buffer the data until the internal buffer is full, and not send anything to the underlying Stream until then.
By calling Flush(), you force it to flush its internal buffer and send the data right away.
If that does not address your question, please edit the question to improve it, making sure to provide a minimal, reproducible example, and any additional details about what you've tried so far to fix the problem and what specifically you need help with.

C# TCP Read welcome message and send Command

I'm having some trouble with a simple TCP Read/Write application where I need to write a command to a device/host. Normally I can do this using a stream.Write() command however with this particular device, it seems to send an initial welcome message back (PJLINK 0) before any command can be sent to it. I can send the commands fine using PuTTY but when using C# I think my connection is closing before I can get my command through.
So my question would be how can I adjust my code below to receive that welcome message and then send my command back (I don't need to read a response) without the TcpClient closing the connection early?
Any help would be greatly appreciated.
using (tcpClientA = new TcpClient())
{
int portA = 4352;
if (!tcpClientA.BeginConnect("10.0.2.201", portA, null, null).AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(1.0)))
{
throw new Exception("Failed to connect.");
}
while (tcpClientA.Connected)
{
using (streamA = tcpClientA.GetStream())
{
if (type == "raw")
{
// Buffer to store the response bytes.
byte[] writeBufferC = Encoding.ASCII.GetBytes("%1 INPT 32$0D"); //Command I need to send
byte[] readBufferC = new byte[tcpClientA.ReceiveBufferSize];
string fullServerReply = null;
using (var writer = new MemoryStream())
{
do
{
int numberOfBytesRead = streamA.Read(readBufferC, 0, readBufferC.Length);
if (numberOfBytesRead <= 0)
{
break;
}
writer.Write(writeBufferC, 0, writeBufferC.Length);
} while (streamA.DataAvailable);
fullServerReply = Encoding.UTF8.GetString(writer.ToArray());
Console.WriteLine(fullServerReply.Trim());
}
}
}
}
}
Update 1
Removed the BeginConnect and Async methods.
using (tcpClientA = new TcpClient())
{
int portA = 4352;
tcpClientA.Connect("10.0.2.201", portA);
while (tcpClientA.Connected)
{
using (streamA = tcpClientA.GetStream())
{
if (type == "raw")
{
byte[] readBufferC = new byte[tcpClientA.ReceiveBufferSize];
byte[] writeBufferC = Encoding.ASCII.GetBytes("%1 INPT 31$0D"); //Command I need to send
string fullServerReply = null;
using (var writer = new MemoryStream())
{
do
{
streamA.Read(readBufferC, 0, readBufferC.Length); //First read
writer.Write(writeBufferC, 0, writeBufferC.Length); //Send command
} while (streamA.DataAvailable);
fullServerReply = Encoding.UTF8.GetString(readBufferC.ToArray());
Console.WriteLine(fullServerReply.Trim());
tcpClientA.Close();
}
}
}
}
}
DataAvailable does not tell you how much data will be sent in the future by the remote side. It's use is almost always a bug. Here, it causes you to randomly exit the loop early.
Read, until you have all the bytes you expect or until the stream is being closed.
Is this a line-based protocol? Instantiate a StreamReader and draw entire lines from the stream.
while (tcpClientA.Connected) accomplishes nothing. Even if it returns true, the connection could be lost 1 nanosecond later. Your code has to deal with that anyway. It should be while (true). This is not a bug, it just shows weak TCP understanding so I point it out.
Remove all usages of ReceiveBufferSize. This value means nothing of significance. Instead, use a fixed buffer size. I find that 4096 works well with not very high throughput connections.
numberOfBytesRead <= 0 should be ==0. Again, not a bug but you don't seem to understand exactly what the API does. This is dangerous.
In the updated code you're not using the return value of streamA.Read which is a bug. You have tried to fix that bug by trimming off the resulting \0 chars. That's just treating the symptoms and is not a true fix.
You need a socket tutorial. This carnage comes because you are not relying on best practices. Socket reading loops are actually rather simple if done right. This code is a collection of what can go wrong.

Null Reference Exception when object is clearly defined

I'm using Unity and .NET to create a TCP client-server relationship.
I actually have everything working where I can send messages back and forth, but now I am hitting a NullReferenceException that is got me scratching my head.
I have a function in my TCPClientListener in my Unity code that calls ReadSocket every Update()
public void SetupSocket(){
socket = new TcpClient(host, port);
stream = socket.GetStream();
writer = new StreamWriter(stream);
reader = new StreamReader(stream);
socketReady = true;
}
public string ReadSocket(){
if(stream.DataAvailable){
return "New Data! " + reader.ReadLine().Replace("<EOF>", "");
}
return "";
}
The above works fine, no problem. WHen the server sends a message, I receive it just fine. But then I add a very simple if statement, and now I'm getting NullReferenceException in regards to reader.
public string ReadSocket() {
if (stream.DataAvailable) {
if (reader.ReadLine().Contains("<EOF>"))
return "New data! " + reader.ReadLine().Replace("<EOF>", "");
}
return "";
}
I hope that I have just been looking at this too long to see the obvious. Why does
if (reader.ReadLine().Contains("<EOF>"))
give me an error!? If I remove it, no error..
The immediate bug is that you are reading two lines. The second read appears to return null. You could have found this by applying standard NRE debugging techniques.
Another bug is that you assume that TCP preserves bessage boundaries. If DataAvailable > 0 this does not mean that an entire line is available. There might be just one byte available. You might find your game blocking unexpectedly.
Usually, it is best to have a continuous read loop running and never pool for data. Just read. When a new line is received act on it.

Windows 8 Store App and Visual Studio 2012, how to stop loadasync() method?

I have made a game that connects to a server to get some high scores. It works fine in the first connection (and then I close the datawriter/reader, and the streamsocket as the connection is supposed to retrieve data in one shot).
But after I attempt a second connection I get a "InvalidOperationException was unhandled by user code". A method was called at a unexpected time.
I used the template for the client connection from the following:
StreamSocket sample
So how can I kill all of the all the threads in the thread pool after this operation, since I think that is what is blocking the second connection?
Also this seems to be a timing issue since it will work on the second connection if I set a break point at the loadasync methods, and step through the code?
Thanks
public async void ScoreUpdate(string input)
{
DataWriter writer = new DataWriter(socket.OutputStream);
DataReader reader = new DataReader(socket.InputStream);
string stringToSend = input;
writer.WriteString(stringToSend);
try
{
uint returnLength = await writer.StoreAsync();
uint sizeFieldCount = await reader.LoadAsync(4);
if (sizeFieldCount != sizeof(uint))
{
// The underlying socket was closed before we were able to read the whole data.
return;
}
uint stringLengthSize = reader.ReadUInt32();
uint stringLength = await reader.LoadAsync((uint)stringLengthSize -4);
UpdateScore = reader.ReadString(stringLength);
socket.Dispose();
socket = null;
}
catch (Exception exception)
{
// If this is an unknown status it means that the error if fatal and retry will likely fail.
if (SocketError.GetStatus(exception.HResult) == SocketErrorStatus.Unknown)
{
throw;
}
socket.Dispose();
socket = null;
}
}
}

TcpClient.EndConnect throws NullReferenceException when socket is closed

I am trying to connect to my server with a TcpClient.BeginConnect / TcpClient.EndConnect combo. However, some things don't work as they should.
The scenario is as follows:
Call to the TcpClient.BeginConnect
Server is intentionally offline (for testing purposes) - thus no connection can be made.
I close the application (client.Close() gets called in the process which closes the socket which in turn stops the async operation)
TcpClient connection callback method happens giving IAsyncResult
Call to the TcpClient.EndConnect method with the given IAsyncResult
NullReferenceException happens on EndConnect (?)
Since the last form (window) was closed, the app should exit - however it does not, at least not until BeginConnect operation completes (which is strange, as callback has already been called).
What happens here is that a NullReferenceException is caught. As you can see from the picture above, neither client nor ar are null. The problem is that the MSDN documentation for the EndConnect does not mention the case in which this exception is thrown.
So basically, I have no idea what is going on. The problem is that I am forced to wait for the app to close (as if the connection operation still waits for a timeout). If a server is online, it connects and disconnects just fine.
What does NullReferenceException in this context mean? How to avoid BeginConnect operation to block the application closing in case the connection can't be established?
Additional notes (requested in comments):
Here is the code to create the client (client is a member variable:
public void Connect()
{
try
{
lock (connectionAccess)
{
if (State.IsConnectable())
{
// Create a client
client = new TcpClient();
client.LingerState = new LingerOption(false, 0);
client.NoDelay = true;
State = CommunicationState.Connecting;
client.BeginConnect(address, port, onTcpClientConnectionEstablished, null);
}
else
{
// Ignore connecting request if a connection is in a state that is not connectable
}
}
}
catch
{
Close(true);
}
}
Also the Close method:
public void Close(bool causedByError)
{
lock (connectionAccess)
{
// Close the stream
if (clientStream != null)
clientStream.Close();
// Close the gateway
if (client != null)
client.Close();
// Empty the mailboxes
incomingMailbox.Clear();
outgoingMailbox.Clear();
State = causedByError ? CommunicationState.CommunicationError : CommunicationState.Disconnected;
}
}
The NullReferenceException is probably due to TcpClient.Client being null.
If you were to follow the MSDN Example for TcpClient.BeginConnect and pass theTcpClient object as the state object:
private void onConnEst(IAsyncResult ar)
{
try
{
TcpClient client = (TcpClient)ar.AsyncState;
if(client!=null && client.Client!=null)
{
client.EndConnect(ar);
}
}
catch(Exception ex){...}
}
This should handle the case when Close() is called before the Callback.
Going back to your problem - how long does it take for the application to eventually close?
This obviously a bug inside the TcpClient class. I have also faced it. TcpClient.Dispose may set Client field to null but EndConnect does not expect that.
I had a similar error and ended up using this code. I am not sure if it will hold with the IASyncResult interface, but there may be a similar way to run this check. I do notice that your ar.AsyncState == null, so perhaps try starting there, i.e. is it null when you connect properly?
private void connConnectCompleted(AsyncCompletedEventArgs e)
{
if (e.Error != null)
{
// Something didn't work...abort captain
CloseSocket();
Console.WriteLine(this.GetType().ToString() + #":Error connecting socket:" + e.Error.Message);
return;
}
// Do stuff with your connection
}
EDIT: Sorry I didn't realise I didn't post what generated my AsyncCompletedEventArgs, which is more related to what you are doing. You will see the reason why I was wondering as to ar.AsyncState being null.
private void OnConnect(IAsyncResult asyncResult)
{
if (OnConnectCompleted == null) return; // Check whether something is using this wrapper
AsyncCompletedEventArgs args;
try
{
Socket outSocket = (Socket) asyncResult.AsyncState;
// Complete connection
outSocket.EndConnect(asyncResult);
args = new AsyncCompletedEventArgs(null);
OnConnectCompleted(this, args);
}
catch (Exception e)
{
args = new AsyncCompletedEventArgs(e.Message);
OnConnectCompleted(this, args);
}
}
This is a know bug.
You should be receiving 'ObjectDisposedException' instead of 'NullReferenceException'.

Categories