I have a program that deals with socket communication asynchronously. The exception I've been getting only occurs in release build (on build machines). The code that causes the problem is really simple routine to start listening for incoming socket connections:
public async Task Listen()
{
try
{
var endpoint = new IPEndPoint(IPAddress.Loopback, Port);
using (Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
Socket.Bind(endpoint);
Socket.Listen(Limit);
while (!Shutdown)
{
var socket = await Socket.AcceptAsync().ConfigureAwait(false);
// some code handling connection
var result = await Socket.ReceiveAsync(state).ConfigureAwait(false);
Received(result, state);
}
}
}
catch (ObjectDisposedException) {}
catch (Exception ex) when (ex is SocketException || ex is ApplicationException || ex is ThreadAbortException)
{
OnError?.Invoke(this, ex);
Dispose();
}
}
AcceptAsync and ReceiveAsync are extension methods that use TPL pattern with Task.Factory.FromAsync. The exact exception is following:
Exception Type: System.InvalidProgramException
Exception Message: Common Language Runtime detected an invalid program.
This seem to occur in:
System.Runtime.CompilerServices.AsyncVoidMethodBuilder.Start
The exception is generated instantly when call is made to this method. Any ideas what might be wrong?
According to MSDN, this exception informs the user about invalid IL code. So something could be broken in the framework. I recommend you to try your luck at Connect.Microsoft. Also, if you're really interested and are looking for a quick fix you may want to inspect the IL code of the failing methods' chain.
Related
I have a class library that I use for making TCP socket connections. Here is the relevant code converted to a console application:
using System;
using System.Net.Sockets;
using System.Threading.Tasks;
namespace ConsoleApp5
{
internal class Program
{
static async Task Main(string[] args)
{
Task receiveTask;
using (TcpClient tcpClient = new TcpClient())
{
// Make a connection
await tcpClient.ConnectAsync("172.25.106.60", 5334).ConfigureAwait(false);
// Start the receive task
receiveTask = RunReceiveTask(tcpClient);
// Let the connection sit for a bit before disconnecting
await Task.Delay(3000).ConfigureAwait(false);
}
// Wait until the receive task has ended
await receiveTask.ConfigureAwait(false);
Console.WriteLine("Press any key to end");
Console.ReadKey();
}
private static async Task RunReceiveTask(TcpClient tcpClient)
{
// This loop continues until the socket reader returns null, which means the socket has been closed,
// either by this application closing it or by the remote disconnecting.
byte[] Buffer = new byte[65535];
int bytesRead;
while (true)
{
try
{
bytesRead = await tcpClient.GetStream().ReadAsync(Buffer, 0, Buffer.Length);
if (bytesRead > 0)
{
// This is where we would process the data received.
}
else
{
// This means the remote end closed the connection
Console.WriteLine("Socket closed by remote");
break;
}
}
catch (ObjectDisposedException)
{
Console.WriteLine("Socket closed by this end");
break;
}
catch (Exception ex)
{
// Some other exception, for example an unexpected drop in the connection
Console.WriteLine($"Socket error: {ex.Message}");
break;
}
}
}
}
}
The code establishes a socket connection to a listening device, waits 3 seconds, and then closes the connection. For the purpose of this test, it doesn't need to send or receive any actual data.
If I create a .Net Framework application with the above code, TCPClient throws an ObjectDisposedException so the console displays "Socket closed by this end", which is the desired behavior and what has always worked for me in the past.
If I put the same code in a .Net Core console application, TCPClient throws an IOException, so the console displays "Socket error: Unable to read data from the transport connection: The I/O operation has been aborted because of either a thread exit or an application request."
This surprises me because the Microsoft documentation seems to indicate that ObjectDisposedException is still to be expected when the stream closes. I could just catch IOException as well, but both sockets that were cleanly closed and those that closed with an error seem to throw that same exception. The linked documentation says I can check the ErrorCode property of the InnerException of the ObjectDisposedException, so I suppose I could make that work.
I guess my question then is did something change in the .Net Core version of System.Net.Sockets, or am I doing something wrong on my side? It seems odd that the documentation would list an ObjectDisposedException when apparently it can't ever be thrown. And if this is expected behavior, is what I listed above the correct way to detect the difference between closures and socket errors?
I have a List of TCP sockets I write data to. If the writing fails, I remove it from the list and just carry on.
At least thats the plan. What happens is, that when a client disconnects, the SocketException escalates and the program crashes, even though that exception is handled. The code is below:
// sockets is type List<Socket>
foreach (Socket s in sockets)
{
String jsonString = skeleton.Marshall();
byte[] jsonBytes = System.Text.Encoding.UTF8.GetBytes(jsonString);
try
{
s.Send(jsonBytes); // boom! System.Net.Sockets.SocketException!
}
catch (System.Net.Sockets.SocketException except)
{
sockets.Remove(s);
Console.WriteLine(except.StackTrace);
}
catch (Exception except)
{
Console.WriteLine(except.StackTrace);
}
}
I don't get why any exception could go through this. I didn't look at the console output because Visual Studio clears that when an exception occurs (at least I didn't see anything meaningful over there)
Thanks for your help!
Edit
As Sebastian Negraszus pointed out, I can't directly remove the Socket from the List, so the code now is
List<Socket> remove = new List<Socket>();
// sockets still is of type List<Socket>
foreach (Socket s in sockets)
{
String jsonString = skeleton.Marshall();
byte[] jsonBytes = System.Text.Encoding.UTF8.GetBytes(jsonString);
try
{
s.Send(jsonBytes);
}
catch (System.Net.Sockets.SocketException except)
{
remove.Add(s);
Console.WriteLine(except.StackTrace);
}
catch (Exception except)
{
Console.WriteLine(except.StackTrace);
}
}
foreach (Socket s in remove)
{
sockets.Remove(s);
}
However, even if the Socket is not removed from the list, it should just escalate here.
Edit 2
This code runs in an event handler, while sockets is being filled in the main Thread, so I assumed the lack of locking caused problems. However, after adding locks, the error still appeared.
main thread:
// ...
sockets = new List<Socket>();
delegateFoo += handlerFunction;
// ...
TcpListener tcpListener = new TcpListener(IPAddress.Any, 20001);
tcpListener.Start();
while (true) {
Socket s = tcpListener.AcceptSocket();
lock (sockets) {
sockets.Add(s);
}
}
handler function:
// ...generate skeleton...
lock (sockets)
{
foreach (Socket s in sockets)
{
String jsonString = skeleton.Marshall();
byte[] jsonBytes = System.Text.Encoding.UTF8.GetBytes(jsonString);
try
{
s.Send(jsonBytes);
}
catch (System.Net.Sockets.SocketException except)
{
remove.Add(s);
Console.WriteLine(except.StackTrace);
}
catch (Exception except)
{
Console.WriteLine(except.StackTrace);
}
}
foreach (Socket s in remove)
{
sockets.Remove(s);
}
}
Bad luck though, the Exception still escalates (at least I think so, the program interrupts in VS and this little window occurs saying "SocketException occured" (I use the German version, so the wording might be different).
The error can be triggered by connecting twice using putty and closing one of the two puttys. The next time Send() is called - boom.
Edit 3: Exception details
I'm sorry these are in German. Translations:
"... ist aufgetreten" = "... occured"
"bei" = "at"
message = "An existing connection has been aborted/terminated by the host computer"
System.Net.Sockets.SocketException ist aufgetreten.
_HResult=-2147467259
_message=Eine bestehende Verbindung wurde softwaregesteuert durch den Hostcomputer abgebrochen
HResult=-2147467259
IsTransient=false
Message=Eine bestehende Verbindung wurde softwaregesteuert durch den Hostcomputer abgebrochen
Source=System
ErrorCode=10053
NativeErrorCode=10053
StackTrace:
bei System.Net.Sockets.Socket.Send(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
InnerException:
And yes, I only Send() once in my program.
Edit 4: Visual Studio weirdness
Okay, it's Visual Studio being weird. I can uncheck the "break on Exceptions of this type" checkbox and then it just continues. So the exception didn't escalate, but nevertheless made the program stop.
I don't get why you would want to break on handled exceptions by default. I figured that if I uncheck that the program just faults. If you have a better solution, I'd be glad to accept your answer.
I assume sockets is a List<T>? You cannot modify the list with sockets.Remove(s); while still inside the foreach loop, because this invalidates the enumerator. The next iteration causes an InvalidOperationException.
Uncheck "break on exceptions of this type" (or whatever it's called in English). Works fine afterwards.
My asynchronous connect code is very rudimentary and is as followed:
private Socket _socket;
public void Connect(IPEndPoint remoteEndPoint, bool persistentConnection)
{
_logger.Trace("Attempting To Connect To " + remoteEndPoint.Address);
_remoteEndPoint = remoteEndPoint;
_persistentConnection = persistentConnection;
_socket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
_socket.BeginConnect(_remoteEndPoint, ConnectCallback, null);
}
The Connect() method is accompanied by ConnectCallback() which is the where the problem I will describe shortly occurs:
private void ConnectCallback(IAsyncResult asyncResult)
{
try
{
_socket.EndConnect(asyncResult);
_logger.Trace("Successfully Connected To " + _remoteEndPoint.Address);
}
catch (SocketException)
{
_logger.Trace("Failed To Connect To " + _remoteEndPoint.Address);
if (_persistentConnection)
{
Thread.Sleep(TimeSpan.FromSeconds(3));
Connect(_remoteEndPoint, true);
return;
}
}
_socketWriter.AssignSocket(_socket);
_socket.BeginReceive(..);
}
My networking code is encapsulated within a single assembly. Today I decided to reference the assembly from another applications and found the ConnectCallback method to behave very oddly.
I make a call to Connect() when the server application is not running. This means it is not physically possible for the connection to succeed. Because the remote end point is not available, I would expect EndConnect to throw an exception. Instead EndConnect appears to succeed because even though the socket is not really connected, my code proceeds to make a call to _socket.BeginReceive which of course, throws an exception because the socket is not connected.
What is especially bizarre is that if I place a break point on the opening try brace and step-through the call back code the exception is thrown and handled.
This happens on local host.
Why am I experiencing this behaviour and how can I ensure that EndConnect throws a SocketException is the connection cannot established consistently?
You only return from the catch if _persistentConnection is true. If not, you call BeginReceive() anyway.
I use VS2012 for my project, I am handling the Socket exception when server cannot send message to target machine but It occurs that when It cannot send msg (I already put it in trycatch) Debugger just break in catch block and say the error without send forward to parent catch block. Please tell me, if I did something wrong.
private void sendMessageToTarget(string Message, IPAddress targetAddress, int port)
{
TcpClient client = new TcpClient();
IPEndPoint server = new IPEndPoint(targetAddress, OUT_MESSAGE_PORT);
Thread senderThread = new Thread(new ThreadStart(delegate()
{
try
{
client.Connect(server);
MemoryStream memstream = new MemoryStream();
NetworkStream netstream = client.GetStream();
byte[] sentString = Encoding.ASCII.GetBytes(Message);
netstream.Write(sentString, 0, sentString.Length);
memstream.Close();
netstream.Close();
client.Close();
}
catch (SocketException ex)
{
throw;
}
}));
senderThread.Start();
} // Sending Message Method
Above is my code for sending message to target
try
{
sendMessageToTarget("CONN_CHECKER", target, OUT_MESSAGE_PORT);
}
catch (Exception se)
{
ConnectedUsers.Remove(target.ToString());
UpdateConnectedUserToTeacher();
if (NeedFollowStudents.Contains(target.ToString()))
{
NeedFollowStudents.Remove(target.ToString());
}
UserLostConnection(this, new EventArgs());
}
And this is the method in another function that I want the action to be performed.
There is no magical marshalling exceptions from one thread to another. It is even almost guaranteed that code after senderThread.Start(); will be executed before code in the thread's delegate.
You function that you pass to Thread constructor becomes top level function on a new thread. If such function throws exception (like you do) this exception will go to AppDomain.UnhandledException event and than normally terminates application.
Your options
revert to synchronous code (all code on one thread)
use existing asynchrnous methods that will notify your code about end of operation. Depending on approach notification can be either via event (similar to WebClient.DownloadStringAsync ) or via callback and calling EndXXXXX like Socket.BeginSend
use async
manually implement synchronization and marshalling exception to original thread.
Note that only synchronous version of the code will work the way you want, all other that use multiple threads will not be able to return exception to the same "parent function" (using async will at least allow your code look the way you want even if it will not work the same way).
This is just a guess, but I believe you should only put a Try/Catch in the parent function and not in the child. When the exception occurs it will show in the parent method. The way you have it written will catch the exception in the child method and it will not get passed back to your parent method.
I create a TCP listener by using the code below:
TCPListener = new TcpListener(IPAddress.Any, 1234);
I start to listen TCP devices by using the code below:
TCPListener.Start();
But here, i don't control if the port is in use. When the port is in use, program gives an exception: "Only one usage of each socket address (protocol/network address/port) is normally permitted.".
How do i handle this exception? I want to warn user that the port is in use.
Put a try/catch block around TCPListener.Start(); and catch SocketException. Also if you are opening multiple connections from your program, then its better if you keep track of your connections in a list and before opening a connection see if you already have a connection opened
It's not a good idea to get an exception to check whether the port is in use or not. Use the IPGlobalProperties object to get to an array of TcpConnectionInformation objects, which you can then interrogate about endpoint IP and port.
int port = 1234; //<--- This is your value
bool isAvailable = true;
// Evaluate current system tcp connections. This is the same information provided
// by the netstat command line application, just in .Net strongly-typed object
// form. We will look through the list, and if our port we would like to use
// in our TcpClient is occupied, we will set isAvailable to false.
IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();
foreach (TcpConnectionInformation tcpi in tcpConnInfoArray)
{
if (tcpi.LocalEndPoint.Port==port)
{
isAvailable = false;
break;
}
}
// At this point, if isAvailable is true, we can proceed accordingly.
For details please read this.
For handling the exception you will use try/catch as habib suggested
try
{
TCPListener.Start();
}
catch(SocketException ex)
{
...
}
Catch it and display your own error message.
Check the exception type and use this type in catch clause.
try
{
TCPListener.Start();
}
catch(SocketException)
{
// Your handling goes here
}
Put it in a try catch block.
try {
TCPListener = new TcpListener(IPAddress.Any, 1234);
TCPListener.Start();
} catch (SocketException e) {
// Error handling routine
Console.WriteLine( e.ToString());
}
Use try-catch blocks and catch the SocketException.
try
{
//Code here
}
catch (SocketException ex)
{
//Handle exception here
}
Well, considering that you're talking about exceptional situation, just handle that exception with suitable try/catch block, and inform a user about a fact.