views:

1094

answers:

5

I am trying to replce the follwing code that works fine

TcpClient oC = new TcpClient(ip, port);
oC = new TcpClient(ip, port);
StreamReader messageReader;

try {
   messageReader = new StreamReader(oC.GetStream(), Encoding.ASCII);
   reply = messageReader.ReadLine();
}

with

try {
   using (messageReader = new StreamReader(oC.GetStream(), Encoding.ASCII))
   {
       reply = messageReader.ReadLine();
   }
}

But I get an InvalidOperationException saying

The operation is not allowed on non-connected sockets.

What is the problem and how can I fix it?

More: I have oc.Connect before this code, so I am connected and when It wants to be used for the first time is works fine, it is only after that that I get that Exception, I played around a bit with it and now I get:

Cannot access a disposed object.\r\nObject name: 'System.Net.Sockets.Socket'.

+12  A: 

Try calling oc.Connect before creating a StreamReader. Until a socket is connected, there is nothing to actually read and hence the exception.

JaredPar
I have oc.Connect before this and it works fine for the 1st time, but the 2nd time it happens, I also get "Cannot access a disposed object.\r\nObject name: 'System.Net.Sockets.Socket'."
Ali
and that's because StreamReader takes ownership of the stream, and closes and disposes the Stream you initiate it with. In this instance, the NetworkStream of the TcpClient. Theres no need to dispose of the StreamReader here.
Sekhat
+1  A: 

Listen to Jared, and your actual exception, the using has nothing to do with it, your try can mask the error and hide the real problem. The real error is that you never actually connected you socket before attempting to read.

Edit:

What it sounds like is happening is that you connect once and then either the connection is severed or an object loses scope. What you need to do in this case is probably trap the disconnect and also recreate the socket that was used to connect to the server in the first place. As soon as that socket is disposed you may not use the same reference again you have to instantiate a new reference and use that.

Do you have a more complete example you could post that would show the scope of your connection vs usage so we can see exactly where the underlying socket is being picked up by the GC?

Quintin Robinson
A: 

I think you're not allowed to define the StreamWriter first, and then use it with 'using'.

Try this:

TcpClient oC = new TcpClient(ip, port);
oC = new TcpClient(ip, port);

try {
   using (StreamWriter messageReader = new StreamReader(oC.GetStream(), Encoding.ASCII))
   {
       reply = messageReader.ReadLine();
   }
}
Bart S.
it's perfectly legal to initialize a streamreader the way he is doing it.
Jared
It's legal, but not recommended by Microsoft, see MSDN or my answer.
Ash
Your code sample instantiates two instances of TcpClient
Richard Szalay
+1  A: 

Also, you declared messageReader as a StreamWriter. Shouldn't it be a StreamReader?

StreamWriter messageReader;

[Fixed by OP]

Another tip, it's best to instantiate an object in the using statement rather then pass it in. It may not be the actual cause of your exception but from MSDN:

You can instantiate the resource object and then pass the variable to the using statement, but this is not a best practice. In this case, the object remains in scope after control leaves the using block even though it will probably no longer have access to its unmanaged resources. In other words, it will no longer be fully initialized. If you try to use the object outside the using block, you risk causing an exception to be thrown. For this reason, it is generally better to instantiate the object in the using statement and limit its scope to the using block.

Ash
That was my mistake , I fixed it.
Ali
No problems, I've added extra to my answer that might be helpful.
Ash
+3  A: 

Just reiterating my comment on Jareds answer.

Ali Commented:

I have oc.Connect before this and it works fine for the 1st time, but the 2nd time it happens, I also get "Cannot access a disposed object.\r\nObject name: 'System.Net.Sockets.Socket'." – Ali (13 mins ago)

I Commented:

"and that's because StreamReader takes ownership of the stream, and closes and disposes the Stream you initiate it with. In this instance, the NetworkStream of the TcpClient. Theres no need to dispose of the StreamReader here"

Sekhat
So, you are saying I can't use "using", I just have to keep it as it is?
Ali
yup, pretty much.
Sekhat