Null Reference Exception when object is clearly defined - c#

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.

Related

What is the correct way to use USBHIDDRIVER for multiple writes?

I am writing an application that needs to write messages to a USB HID device and read responses. For this purpose, I'm using USBHIDDRIVER.dll (https://www.leitner-fischer.com/2007/08/03/hid-usb-driver-library/ )
Now it works fine when writing many of the message types - i.e. short ones.
However, there is one type of message where I have to write a .hex file containing about 70,000 lines. The protocol requires that each line needs to be written individually and sent in a packet containing other information (start, end byte, checksum)
However I'm encountering problems with this.
I've tried something like this:
private byte[] _responseBytes;
private ManualResetEvent _readComplete;
public byte[][] WriteMessage(byte[][] message)
{
byte[][] devResponse = new List<byte[]>();
_readComplete = new ManualResetEvent(false);
for (int i = 0; i < message.Length; i++)
{
var usbHid = new USBInterface("myvid", "mypid");
usbHid.Connect();
usbHid.enableUsbBufferEvent(UsbHidReadEvent);
if (!usbHid.write(message)) {
throw new Exception ("Write Failed");
}
usbHid.startRead();
if (!_readComplete.WaitOne(10000)) {
usbHid.stopRead();
throw new Exception ("Timeout waiting for read");
}
usbHid.stopRead();
_readComplete.Reset();
devResponse.Add(_responseBytes.ToArray());
usbHid = null;
}
return devResponse;
}
private void ReadEvent()
{
if (_readComplete!= null)
{
_readComplete.Set();
}
_microHidReadBytes = (byte[])((ListWithEvent)sender)[0];
}
This appears to work. In WireShark I can see the messages going back and forth. However as you can see it's creating an instance of the USBInterface class every iteration. This seems very clunky and I can see in the TaskManager, it starts to eat up a lot of memory - current run has it above 1GB and eventually it falls over with an OutOfMemory exception. It is also very slow. Current run is not complete after about 15 mins, although I've seen another application do the same job in less than one minute.
However, if I move the creation and connection of the USBInterface out of the loop as in...
var usbHid = new USBInterface("myvid", "mypid");
usbHid.Connect();
usbHid.enableUsbBufferEvent(UsbHidReadEvent);
for (int i = 0; i < message.Length; i++)
{
if (!usbHid.write(message)) {
throw new Exception ("Write Failed");
}
usbHid.startRead();
if (!_readComplete.WaitOne(10000)) {
usbHid.stopRead();
throw new Exception ("Timeout waiting for read");
}
usbHid.stopRead();
_readComplete.Reset();
devResponse.Add(_responseBytes.ToArray());
}
usbHid = null;
... now what happens is it only allows me to do one write! I write the data, read the response and when it comes around the loop to write the second message, the application just hangs in the write() function and never returns. (Doesn't even time out)
What is the correct way to do this kind of thing?
(BTW I know it's adding a lot of data to that devResponse object but this is not the source of the issue - if I remove it, it still consumes an awful lot of memory)
UPDATE
I've found that if I don't enable reading, I can do multiple writes without having to create a new USBInterface1 object with each iteration. This is an improvement but I'd still like to be able to read each response. (I can see they are still sent down in Wireshark)

Why do these two StreamWriter constructors give me different results?

Long story short I am trying to send a string via TcpClient using StreamWriter.
Without changing any other code except swapping out these samples. They produce different results.
In code sample 1 the StreamReader picks up that it has DataAvailable and the message is received.
In code sample 2 it does not have DataAvailable so no message is received. I need to keep my underlying stream open hence needing to use the constructor of StreamWrite in sample 2.
Sample 1 - Write Method
public void SendMessage(string message)
{
message = "TestMessage";
//WORKING - Sample 1
using (var sw = new StreamWriter(stream))
{
sw.Write(message);
sw.Flush();
}
}
Sample 2 - Write Method
public void SendMessage(string message)
{
message = "TestMessage";
//NOT WORKING - Sample 2
var encoding = new UTF8Encoding(false, true);
using (var sw = new StreamWriter(stream, encoding, 1024, true))
{
sw.Write(message);
sw.Flush();
}
}
Read Method
public string ReadMessage()
{
if (!stream.DataAvailable)
return null;
//I have also tried
//if(sr.Peek() == 0)
// return null;
string message = sr.ReadToEnd();
return message;
}
NOTE: If I put both samples together with the working one last I get the message received "TestMessageTestMessage" so it is definitely writing to stream however it is not setting DataAvailable to true?
Any Idea's why?
The problem is your ReadToEnd() command which blocks indefinitely on a NetworkStream which has no end until closed. I tested your code and I went past the DataAvailable query and blocked on the ReadToEnd() command.
Your method that uses a constructor that allows the BaseStream to stay open means that you never have an end to your stream. When the working method closes the stream the ReadMessage method returns with everything in the stream.
The solution: Do not attempt to read to the end. Read in blocks while the data is available or introduce a terminating character and read to that character.
From MSDN:
ReadToEnd assumes that the stream knows when it has reached an end. For interactive protocols in which the server sends data only when you ask for it and does not close the connection, ReadToEnd might block indefinitely because it does not reach an end, and should be avoided.

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.

How to restart a Network Stream after a SocketException

I have a piece of code that reads a JSON stream from a server on the public internet. I am trying to make the connection a little more robust by catching the exception and trying to restart it on a given interval but I haven't been able to figure out how to restart it.
My stream code is as follows
TcpClient connection = new TcpClient(hostname, port);
NetworkStream stream = connection.GetStream();
thread = new Thread(ProcessStream);
thread.Start(stream);
My ProcessStream method is
private void ProcessStream(object stream)
{
Stream source = (NetworkStream)stream;
byte[] line;
int count;
const int capacity = 300;
ReadState readState;
while ((readState = ReadStreamLine(source, out line, out count, capacity)) != ReadState.EOF && _stopFeed == false)
{
if (readState != ReadState.Error && count > 4)
{
byte[] line1 = new byte[count];
Array.Copy(line, line1, count);
Process(line1); // return ignored in stream mode
}
else
{
ReadFail(line, count);
}
}
}
and my ReadStream function takes the stream s, does an s.ReadByte and then catches the exception when the network connection is broken. It is here that I am not sure how to try and restart the stream on a timed basis. It does not restart automatically when the network is restored.
That is not possible. It is like you calling your friend on the phone and he hangs up in the middle of a conversation. No matter how long you wait, you'll never hear from him again. All you can do is hang-up the phone and dial the number again. Unless the server supports restartable downloads (use HttpWebRequest.AddRange), you'll have to download the json again from the beginning.
If this happens a lot, so it can't be explained by the server going offline or getting overloaded, do keep in mind that the server might well be doing this on purpose. Usually because you exceeded some kind of quota. Talk to the server owner, they typically have a paid plan to allow you to use more resources.
From what I can tell, you instantiate your TcpClient before you start your method. So, in order to restart your stream, you need to re-instantiate or re-initialize your connection stream before trying again.
try
{
// Do something
}
catch (Exception ex)
{
// Caught your exception, might be ideal to log it too
// Have a count, if count is less than goal
// Call your method again
if (count < 5)
{
// re-initialize or re-instantiate connection
TcpClient connection = new TcpClient(host, port);
NetworkStream stream = connection.GetStream();
ProcessStream(stream);
}
}
I hope this helps.
You coculd at first add your stream to a static list of running streams and after finishing reading remove it from there.
Remember to use locking!
Then in the NetworkGone-Catch you can copy your list to a "todoAfterNetworkIsUpAgain"-List and start a timer that checks for network and after your network is up again restarts reading the streams again.
This Might look a bit tuff but its not the case.
Use Recursion and threading in a better way and your problem might get resolved
For Recursion
http://www.dotnetperls.com/recursion
For Threading
Take a look to msdn documentation or take consepts from albahari

TCP data occasionally received in wrong order and incomplete

I have created TCP Server application in Java, and a client application in C#. When i am sending data, the client sometimes receives data out of order, and sometimes parts miss entirely. Basically, the code i use in the server (java) looks like this (stripped):
ServerSocket welcomeSocket = new ServerSocket(port);
Socket connectionSocket = welcomeSocket.accept();
outputStream = new DataOutputStream(socket.getOutputStream()); //Create stream
outputStream.writeBytes(message + "\n");
outputStream.flush();
I use "\n" as a delimiter. On the client side (C#) i use the following code:
private const char Delimiter = '\n';
tcpclnt = new TcpClient();
tcpclnt.NoDelay = true;
tcpclnt.Client.DontFragment = true;
tcpclnt.Connect(ip, port);
//This function is executed in a separate thread
public void Receive()
{
try
{
stream = tcpclnt.GetStream();
streamreader = new StreamReader(stream);
this.Connected = true;
while (Connected)
{
string line = ReadLine(streamreader);
Console.WriteLine("Received data: " + line);
}
}
}
private string ReadLine(StreamReader reader)
{
bool finished = false;
string line = "";
while (finished == false)
{
int asciiNumber = reader.Read();
char character = Convert.ToChar(asciiNumber);
if (!character.Equals(Delimiter))
line += character;
else finished = true;
}
return line;
}
The code is not very complicated. However, the data sent from the server is not always received correctly in the client. As an example, I should receive the following two strings:
"5_8_1" and "6_LEVELDATA"
What i get (sometimes) however, is this: "5_8_61" and "_LEVELDATA"
Another example: "5_4_1" and "6_LEVELDATA" result in one single string: "5_6_LEVELDATA"
This seems like some small problem, but it does in fact pretty much ruin my application. I have read a lot of posts, but the only answers i have read are either "this shouldnt happen with TCP" or "send the length of the tcp message first" which would not help in any way in this case, because the problem isn't the data being split up in multiple packages, it simply isn't arriving in the right order, which is something TCP should do.
I am 100% sure the string is always complete before it is being sent by the Java application.
I really wonder what i'm doing wrong here. Is something messed up bad in my code? I would appreciate any help with this problem. Thanks in advance.
After trying Wireshark, it appears my problem existed in the server. Apparently every TCP-message was sent in a seperate thread. Thank you for all of your comments! My problem is solved now.

Categories