I have written the code for Server/Client program in C#. Without using the Thread, it is working fine. If I use Thread, I am getting following error message.
The thread '' (0x9a8) has exited with code 0 (0x0).
Sample code
public class MyServer{
public MyServer (){
...
...
System.Threading.Thread socThread = new System.Threading.Thread(new System.Threading.ThreadStart(receiveSockets));
socThread.Start();
}
private void receiveSockets()
{
try
{
while(true){
IPAddress ipadd = IPAddress.Parse(systemIPAddress);
TcpListener tcp = new TcpListener(ipadd, 8001);
tcp.Start();
Console.WriteLine("Waiting for client in 8001 port no");
Socket socket = tcp.AcceptSocket();
Console.WriteLine("Client address : " + socket.RemoteEndPoint);
System.Threading.Thread socThread = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(receiveData));
socThread.Start(socket);
}
}
catch (Exception e)
{
Console.WriteLine("Error in receive Sockets : " + e.Message);
}
}
private void receiveData(object obj)
{
try
{
while(true){
Socket socket = (Socket)obj;
byte[] data = new byte[1000];
int status = socket.Receive(data);
Console.WriteLine("Received 1.");
string content = Encoding.UTF8.GetString(data, 0, 1000);
Console.WriteLine("Received data 1 : " + content);
}
}
catch (Exception e)
{
Console.WriteLine("Error in receive Data : " + e.Message);
}
}
static void Main(string[] args){
MyServer server = new MyServer();
}
Client Program
static void Main(string[] args)
{
TcpClient tcp = new TcpClient();
tcp.Connect("192.168.1.11", 8001);
Stream stream = tcp.GetStream();
String msg = "Testing...";
byte[] content = new byte[msg.Length * sizeof(char)];
System.Buffer.BlockCopy(msg.ToCharArray(), 0, content, 0, content.Length);
stream.Write(content, 0, content.Length);
}
I am getting the following output.
IP Addrress : 192.168.1.11
Waiting for client in 8001 port no
Client address : 192.168.1.11:50140
The thread '' (0x9a8) has exited with code 0 (0x0).
A first chance exception of type 'System.Net.Sockets.SocketException' occurred in System.dll
The thread '' (0x1760) has exited with code 0 (0x0).
Error in receive Data : An existing connection was forcibly closed by the remote host
The program '[1396] Window_Server.vshost.exe: Managed (v4.0.30319)' has exited with code 0 (0x0).
Please help me to fix this issue.
You need to figure out why you are throwing a socket exception. If you read the documentation for Socket.Receive You would see this section:
Note
If you receive a SocketException, use the SocketException.ErrorCode property to obtain the specific error code.
After you have obtained this code, refer to the Windows Sockets
version 2 API error code documentation in the MSDN library for a
detailed description of the error.
Follwing that link shows you how to read the error code:
The ErrorCode property contains the error code that is associated with
the error that caused the exception.
The default constructor for SocketException sets the ErrorCode
property to the last operating system error that occurred. For more
information about socket error codes, see the Windows Sockets version
2 API error code documentation in MSDN.
Which should bring you to the error codes page.
Now depending on your error code, which you have not provided, you can diagnose the network issue.
"The thread '' (0x9a8) has exited with code 0 (0x0)." is not an error. It is simply telling you that a background thread has exited. Zero means the thread ran and exited successfully.
The exception is in receiveData(object obj) as you should be able to tell, given the exception , "Error in receive Data : An existing connection was forcibly closed by the remote host".
If you post the client program you are working with I might be able to help.
The problem is that Main() does not wait for the sockets to be done with their jobs. As soon as it has created the threads, it exists... And the threads are destroyed.
You need to wait for the socket-handling threads by using events of some sort, or by sleeping, from Main() - or from MyServer(), as long as the program exists only when the whole job is done.
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 an chat room application that has two parts server and client.
server part can receive data from multi clients. So far so good.
But when one of the client leaves, the software gets an error!
this is server source code:
I commented on the line where the software gets an error !!!
Socket _server;
private void StartServer()
{
_server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_server.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 100010));
_server.Listen(1);
while (true) {
Socket client = _server.Accept();
Thread rd = new Thread(ReceiveData);
rd.Start(client);
}
}
public void ReceiveData(object skt)
{
Socket socket = (Socket)skt;
while (true) {
byte[] buffer = new byte[1024];
int r = socket.Receive(buffer);// when a client leave here get an error !!!
if (r > 0)
Console.WriteLine(socket.RemoteEndPoint.Address + ": " + Encoding.Unicode.GetString(b));
}
}
Error:
An unhandled exception of type 'System.Net.Sockets.SocketException' occurred in System.dll
Additional information: An existing connection was forcibly closed by the remote host
How can i fix it ?
You should just handle the exception:
try
{
// code that uses the socket
}
catch (SocketException e) when (e.SocketErrorCode is SocketError.ConnectionAborted)
{
// code to handle the situation gracefully
}
Or if you are using an older compiler:
try
{
// code that uses the socket
}
catch (SocketException e)
{
if(e.SocketErrorCode != SocketError.ConnectionAborted)
{
// rethrow the exception
throw;
}
// code to handle the situation gracefully
}
I've got a listener socket that accepts, receives and sends as a TCP server typically does. I've given my accept and receive code below, it's not that different from the example on Microsoft's documentation. The main difference is that my server doesn't kill a connection after it stops receiving data (I don't know if this is a bad design or not?).
private void on_accept(IAsyncResult xResult)
{
Socket listener = null;
Socket handler = null;
TStateObject state = null;
Task<int> consumer = null;
try
{
mxResetEvent.Set();
listener = (Socket)xResult.AsyncState;
handler = listener.EndAccept(xResult);
state = new TStateObject()
{
Socket = handler
};
consumer = async_input_consumer(state);
OnConnect?.Invoke(this, handler);
handler.BeginReceive(state.Buffer, 0, TStateObject.BufferSize, 0, new AsyncCallback(on_receive), state);
}
catch (SocketException se)
{
if (se.ErrorCode == 10054)
{
on_disconnect(state);
}
}
catch (ObjectDisposedException)
{
return;
}
catch (Exception ex)
{
System.Console.WriteLine("Exception in TCPServer::AcceptCallback, exception: " + ex.Message);
}
}
private void on_receive(IAsyncResult xResult)
{
Socket handler = null;
TStateObject state = null;
try
{
state = xResult.AsyncState as TStateObject;
handler = state.Socket;
int bytesRead = handler.EndReceive(xResult);
UInt16 id = TClientRegistry.GetIdBySocket(handler);
TContext context = TClientRegistry.GetContext(id);
if (bytesRead > 0)
{
var buffer_data = new byte[bytesRead];
Array.Copy(state.Buffer, buffer_data, bytesRead);
state.BufferBlock.Post(buffer_data);
}
Array.Clear(state.Buffer, 0, state.Buffer.Length);
handler.BeginReceive(state.Buffer, 0, TStateObject.BufferSize, 0, new AsyncCallback(on_receive), state);
}
catch (SocketException se)
{
if(se.ErrorCode == 10054)
{
on_disconnect(state);
}
}
catch (ObjectDisposedException)
{
return;
}
catch (Exception ex)
{
System.Console.WriteLine("Exception in TCPServer::ReadCallback, exception: " + ex.Message);
}
}
This code is used to connect to an embedded device and works (mostly) fine. I was investigating a memory leak and trying to speed up the process a bit by replicating exactly what the device does (our connection speeds are in the realm of about 70kbps to our device, and it took an entire weekend of stress testing to get the memory leak to double the memory footprint of the server).
So I wrote a C# program to replicate the data transactions, but I've run into an issue where when I disconnect the test program, the server gets caught in a loop where it endlessly has its on_receive callback called. I was under the impression that BeginReceive wouldn't be triggered until something was received, and it seems to call on_receive, ends the receiving like an async callback should do, process the data, and then I want the connection to await more data so I call BeginReceive again.
The part of my test program where the issue occurs is in here:
private static void read_write_test()
{
mxConnection = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
mxConnection.Connect("12.12.12.18", 10);
if (mxConnection.Connected)
{
byte[] data = Encoding.ASCII.GetBytes("HANDSHAKESTRING"); //Connect string
int len = data.Length;
mxConnection.Send(data);
data = new byte[4];
len = mxConnection.Receive(data);
if (len == 0 || data[0] != '1')
{
mxConnection.Disconnect(false);
return;
}
}
//Meat of the test goes here but isn't relevant
mxConnection.Shutdown(SocketShutdown.Both);
mxConnection.Close();
}
Up until the Shutdown(SocketShutdown.Both) call, everything works as expected. When I make that call however, it seems like the server never gets notification that the client has closed the socket and gets stuck in a loop of endlessly trying to receive. I've done my homework and I think I am closing my connection properly as per this discussion. I've messed around with the disconnect section to just do mxConnection.Disconnect(false) as well, but the same thing occurs.
When the device disconnects from the server, my server catches a SocketException with error code 10054, which documentation says:
Connection reset by peer.
An existing connection was forcibly closed
by the remote host. This normally results if the peer application on
the remote host is suddenly stopped, the host is rebooted, the host or
remote network interface is disabled, or the remote host uses a hard
close (see setsockopt for more information on the SO_LINGER option on
the remote socket). This error may also result if a connection was
broken due to keep-alive activity detecting a failure while one or
more operations are in progress. Operations that were in progress fail
with WSAENETRESET. Subsequent operations fail with WSAECONNRESET.
I've used this to handle the socket being closed and has worked well for the most part. However, with my C# test program, it doesn't seem like it works the same way.
Am I missing something here? I'd appreciate any input. Thanks.
The main difference is that my server doesn't kill a connection after it stops receiving data (I don't know if this is a bad design or not?).
Of course it is.
it seems like the server never gets notification that the client has closed the socket and gets stuck in a loop of endlessly trying to receive
The server does get notification. It's just that you ignore it. The notification is that your receive operation returns 0. When that happens, you just call BeginReceive() again. Which starts a new read operation. Which…returns 0! You just keep doing that over and over again.
When a receive operation returns 0, you're supposed to complete the graceful closure (with a call to Shutdown() and Close()) that the remote endpoint started. Do not try to receive again. You'll just keep getting the same result.
I strongly recommend you do more homework. A good place to start would be the Winsock Programmer's FAQ. It is a fairly old resource and doesn't address .NET at all. But for the most part, the things that novice network programmers are getting wrong in .NET are the same things that novice Winsock programmers were getting wrong twenty years ago. The document is still just as relevant today as it was then.
By the way, your client-side code has some issues as well. First, when the Connect() method returns successfully, the socket is connected. You don't have to check the Connected property (and in fact, should never have to check that property). Second, the Disconnect() method doesn't do anything useful. It's used when you want to re-use the underlying socket handle, but you should be disposing the Socket object here. Just use Shutdown() and Close(), per the usual socket API idioms. Third, any code that receives from a TCP socket must do that in a loop, and make use of the received byte-count value to determine what data has been read and whether enough has been read to do anything useful. TCP can return any positive number of bytes on a successful read, and it's your program's job to identify the start and end of any particular blocks of data that were sent.
You missed this in the documentation for EndReceive() and Receive():
If the remote host shuts down the Socket connection with the Shutdown method, and all available data has been received, the Receive method will complete immediately and return zero bytes.
When you read zero bytes, you still start another BeginReceive(), instead of shutting down:
if (bytesRead > 0)
{
var buffer_data = new byte[bytesRead];
Array.Copy(state.Buffer, buffer_data, bytesRead);
state.BufferBlock.Post(buffer_data);
}
Array.Clear(state.Buffer, 0, state.Buffer.Length);
handler.BeginReceive(state.Buffer, 0, TStateObject.BufferSize, 0, new AsyncCallback(on_receive), state);
Since you keep calling BeginReceive on a socket that's 'shutdown', you're going to keep getting callbacks to receive zero bytes.
Compare with the example from Microsoft in the documentation for EndReceive():
public static void Read_Callback(IAsyncResult ar){
StateObject so = (StateObject) ar.AsyncState;
Socket s = so.workSocket;
int read = s.EndReceive(ar);
if (read > 0) {
so.sb.Append(Encoding.ASCII.GetString(so.buffer, 0, read));
s.BeginReceive(so.buffer, 0, StateObject.BUFFER_SIZE, 0,
new AsyncCallback(Async_Send_Receive.Read_Callback), so);
}
else{
if (so.sb.Length > 1) {
//All of the data has been read, so displays it to the console
string strContent;
strContent = so.sb.ToString();
Console.WriteLine(String.Format("Read {0} byte from socket" +
"data = {1} ", strContent.Length, strContent));
}
s.Close();
}
}
I'm working on small program for learning purpose.
My program is simple Telnet console.
Using visual studio 2010 Express I created pretty cool UI now I'm trying to establish communication with remote server(Creston control processor). I copied and pasted class from this Microsoft article and when I execute the class the program freezes. I'm not sure how to properly describe what happens but in basic word all controls(including close button) stop working.
Here code for my class:(I added few debug lines);
public class StateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 256;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
public string TempString = string.Empty;
public int TotalBytesRead = 0;
public char[] charBuffer = new char[1000];
}
public class AsynchronousClient
{
// The port number for the remote device.
private const int port = 23;
// ManualResetEvent instances signal completion.
private static ManualResetEvent connectDone =
new ManualResetEvent(false);
private static ManualResetEvent sendDone =
new ManualResetEvent(false);
private static ManualResetEvent receiveDone =
new ManualResetEvent(false);
// The response from the remote device.
private static String response = String.Empty;
public AsynchronousClient()
{
}
public void New()
{
StartClient();
}
private static void StartClient()
{
// Connect to a remote device.
try
{
// Establish the remote endpoint for the socket.
// The name of the
// remote device is "host.contoso.com".
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("10.106.6.60"), port);
// Create a TCP/IP socket.
Socket client = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Connect to the remote endpoint.
client.BeginConnect(remoteEP,
new AsyncCallback(ConnectCallback), client);
connectDone.WaitOne();
Console.WriteLine("StartSend");
// Send test data to the remote device.
//Send(client, "hostname\n");
//sendDone.WaitOne();
Console.WriteLine("WaitForResponse");
// Receive the response from the remote device.
Receive(client);
receiveDone.WaitOne();
// Write the response to the console.
Console.WriteLine("Read From Socket : {0}", response);
Console.WriteLine("ReleaseSocket");
// Release the socket.
client.Shutdown(SocketShutdown.Both);
client.Disconnect(true);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void ConnectCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete the connection.
client.EndConnect(ar);
Console.WriteLine("Socket connected to {0}",
client.RemoteEndPoint.ToString());
// Signal that the connection has been made.
connectDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void Receive(Socket client)
{
try
{
// Create the state object.
Console.WriteLine("Receive");
StateObject state = new StateObject();
state.workSocket = client;
// Begin receiving the data from the remote device.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void ReceiveCallback(IAsyncResult ar)
{
try
{
// Retrieve the state object and the client socket
// from the asynchronous state object.
Console.WriteLine("Start Read");
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
// Read data from the remote device.
int bytesRead = client.EndReceive(ar);
Console.WriteLine("Bytes read: {0}", bytesRead);
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.
string tsTempString = Encoding.ASCII.GetString(state.buffer, 0, bytesRead);
state.TempString += tsTempString;
Console.WriteLine("String {0}", tsTempString);
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
// Get the rest of the data.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
else
{
// All the data has arrived; put it in response.
if (state.sb.Length > 1)
{
response = state.sb.ToString();
}
// Signal that all bytes have been received.
receiveDone.Set();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void Send(Socket client, String data)
{
Console.WriteLine("Send");
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
client.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), client);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
Console.WriteLine("SendCallBack");
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = client.EndSend(ar);
Console.WriteLine("Sent {0} bytes to server.", bytesSent);
// Signal that all bytes have been sent.
sendDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
When connecting to the server it responds with following lines:
CP3 Console
Warning: Another console session is open
CP3>
When I run the program i get following output:
Socket connected to 10.106.6.60:23
StartSend
WaitForResponse
Receive
Start Read
Bytes read: 13
String CP3 Console
Start Read
Bytes read: 43
String Warning: Another console session is open
Start Read
Bytes read: 6
String
CP3>
The thread '<No Name>' (0x1d80) has exited with code 0 (0x0).
The thread '<No Name>' (0x24bc) has exited with code 0 (0x0).
I tried different methods of reading stream but no successes. The program still hangs up at the same spot.
It seems as after reading last byte ">" the program does not re-executes method "ReceiveCallback" to exit out of the loop.
I get feeling it has something with the way "ReceiveCallback" is being called but I could not figure out what client.beginReceive() parameters actually do.
To expand on Roemer's answer: EndReceive will return 0 only if the conversation has terminated. That usually means a TCP packet with the FIN or RST flag has been received, most often because the peer - in your case, the server - closed its endpoint or exited. (There are various other cases; for example, a firewall or intermediate node could generate an RST.)
(Roemer wrote "BeginReceive never returns zero...", but clearly meant EndReceive, since BeginReceive returns the IAsyncResult object.)
If the peer doesn't close its end of the conversation, EndReceive won't return 0, and you'll never enter the else branch of your callback that invokes receiveDone.Set().
It's not entirely clear from your description exactly how the server behaves, but its last send of 6 bytes was clearly a newline followed by the "CP3>" prompt. At that point it's waiting for your client to send something. It's not going to close the connection.
TCP is a bytestream service - it doesn't provide record boundaries. So there's no way for the socket layer to know when the server is "done sending", except when the server closes the connection. You have three choices for your client:
Parse the server's output as you receive it and recognize when it's waiting for input (in this case, that means recognizing the "CP3>" prompt)
Decide the server's done after some arbitrary time has passed with no further data from the server
Don't worry about it, and simply output data from the server as you receive it
That third option is the simplest one. Do your first BeginReceive after making the connection. Then, in your callback method, if the conversation is still open and no errors have occurred, process the data you've received and invoke BeginReceive again.
To be honest, this example from microsoft is really bad.
In general, client.EndReceive never returns 0 except when the connection is closed. So receiveDone.Set will never be called in your example. In a more real-live example, you should check the received data in ReceiveCallback and when a keyword (like "Login: ") occurs, set the receiveDone and start sending (the login data for example) and the start receiving again and so on. You might also want to look at the async/await keyword (.net 4.5) and maybe upgrade to Visual Studio community edition :)
There are tons of examples on codeproject or found via google (like http://blogs.msdn.com/b/pfxteam/archive/2011/12/15/10248293.aspx).
i wrote a console application. i used socket programming .
i get error in below cod. transfer speed of data is 10ms . after a period of time i get a error on " while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)" line .
while (true)
{
TcpClient tcpClient = tcpListener.AcceptTcpClient();
NetworkStream stream = tcpClient.GetStream();
String data = null;
int i;
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
// Translate data bytes to a ASCII string.
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
...
}
error :
An unhandled exception of type 'System.IO.IOException' occurred in
System.dll Additional information: Unable to read data from the
transport connection: A connection attempt failed because the
connected party did not properly respond after a period of time, or
established connection failed because connected host has failed to
respond.
When you do IO stuff or network stuff, your code needs to be able to handle excpetional circumstances, so say with a socket, the server suddenly shuts down their end of a connection, your code needs to be able to handle that. And your code isn't doing anything with that exception.
To do this you need to put your code in a try/catch block
try
{
// put socket code stuff here
}
catch(IOException ioe)
{
// put excpetion code here.
}
Hope this helps.