Close Client Socket on disconnect - c#

I have server application that listens for clients.
Let's client lost internet connection and lost connection with server.
Does server automatically check when a client was disconnected? If not how may I implement such thing?
Main.cs http://pastebin.com/fHYpErz7
ServerSocket.cs: http://pastebin.com/erw4tzdp
Client.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
namespace jM2
{
class Client
{
private int clientConnectionID;
private Socket clientSocket;
private string clientIP;
private byte[] clientBuffer = new byte[1024];
public Client(int connectionID, Socket connectionSocket)
{
clientConnectionID = connectionID;
clientSocket = connectionSocket;
clientIP = connectionSocket.RemoteEndPoint.ToString();
clientSocket.BeginReceive(clientBuffer, 0, clientBuffer.Length, SocketFlags.None, new AsyncCallback(dataArrival), null);
}
public void Disconnect()
{
clientSocket.Close();
}
private void dataArrival(IAsyncResult iar)
{
int bytesReceived = clientSocket.EndReceive(iar);
clientSocket.BeginReceive(clientBuffer, 0, clientBuffer.Length, SocketFlags.None, new AsyncCallback(dataArrival), null);
}
}
}

See my answer to this question:
TcpClient.Close doesn't close the connection
Basically no one knows if the connection is closed until you try to send data. If it fails, the connection is closed.

Based on what Chris Haas said, I may be wrong, however I have previously written a TCP server and detected closed connections when I received 0 bytes. In other words, in your dataArrival method, if bytesReceived was 0, this would indicate the connection had closed. This seemed to work through fairly extensive testing.

I recommend a type of "poll" or "heartbeat" message, as described here.

Related

Windows form freezes when using synchronous TCP Client

I am writing a Windows Forms application in C# (single thread). The application uses a synchronous TCP client that connects to a remote server and messages are passed both ways (via a socket). The client sends a message and the server should respond with a message. The form is populated with network information (Textboxes), such as IP address, port number etc. This all works as expected and I can pass messages over the network.
But I have observed that the application sometimes becomes unresponsive for a moment, e.g. when trying to connect to an unreachable IP address. I have tried to investigate and it seems to me that the solution is to either use classical threading or to switch to an asynchronous TCP client, in order not to block the UI thread. I would like to try the asynchronous client, but I am not sure how this should be implemented.
Currently I connect, send and receive synchronously. Should it be possible to "just” add the async keywork to the method declarations and add the await keywork before the stream.Read or stream.Write?
I have seen various methods such as TcpClient.ConnectAsync, NetworkStream.BeginRead, NetworkStream.BeginWrite, NetworkStream.ReadAsync and NetworkStream.WriteAsync with various different examples, so I am confused about which methods to use and how to use them.
My code:
using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Collections;
NetworkStream stream;
TcpClient client;
int port;
//Button click event to connect with the server from the client
private void btn_Connect_Click(object sender, EventArgs e)
{
if (!int.TryParse(txtBox_Port.Text, out port))
{
MessageBox.Show("Port number not valid.");
}
try
{
client = new TcpClient(txtBox_IP_Addr.Text, port);
//UI "hangs/freezes" for several seconds if this connection cannot be established
txtBox_Connection_Status.Text = "Connection made with " + txtBox_IP_Addr.Text + " on port " + txtBox_Port.Text;
}
catch
{
txtBox_Connection_Status.Text = "Connection not established";
}
}
//Button click event to send data from the client to the server and receive response from the server
private void btn_Send_Click(object sender, EventArgs e)
{
try
{
byte[] message = { 0x00, 0x07 };
stream = client.GetStream();
stream.Write(message, 0, message.Length);
}
catch
{
txtBox_Connection_Status.Text = "No connection";
}
try
{
byte[] buffer = new byte[4096];
int no_read_bytes = stream.Read(buffer, 0, buffer.Length);
//UI "hangs/freezes" if no data is received
}
catch
{
txtBox_Connection_Status.Text = "No connection";
}
}

C# SocketException when accepting connections

I have been trying to learn about sockets for the past day or so. I thought it would be a good idea to make a basic chat client and server to learn with, I have tried to make an asynchronous server so I don't need to use loads of threads etc and I have came into an issue I simply can't fix. When I start my server, it goes through all ok and waits at the point where it needs to wait for a connection. I then start up my makeshift 'client' that simply sends a string for now and my server crashes with a SocketException with the message
Additional information: A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
I don't see how my socket is not connected when it has to accept the connection in the first place. I have been using this tutorial (https://msdn.microsoft.com/en-us/library/fx6588te(v=vs.110).aspx) as a guide and have looked at both my code and the tutorial and still don't understand what I am doing wrong, can anyone help me?
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Chat_Application
{
class Server
{
private Socket serverSocket = null;
private volatile ArrayList connections = null; // will hold all client sockets
private const int port = 1090;
private IPAddress ipAddress = null;
private IPEndPoint ipEndPoint = null;
private Thread listenThread = null; // seperate thread to run the server
private ManualResetEvent allDone = null;
public Server()
{
this.serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
this.connections = new ArrayList();
ipAddress = IPAddress.Parse(GetLocalIPv4(NetworkInterfaceType.Ethernet));
ipEndPoint = new IPEndPoint(ipAddress, port);
listenThread = new Thread(StartListen);
allDone = new ManualResetEvent(false);
}
public void Start()
{
listenThread.Start();
}
public void StartListen()
{
this.serverSocket.Bind(ipEndPoint);
this.serverSocket.Listen(20);
Program.mainWin.console.Text += "\n<INFO> Socket bound, listening for connections...";
while (true)
{
allDone.Reset();
serverSocket.BeginAccept(new AsyncCallback(AcceptConnectionAsync), serverSocket);
Program.mainWin.console.Text += "\n<INFO> Conncetion accepted...";
allDone.WaitOne();
}
}
public void AcceptConnectionAsync(IAsyncResult AR)
{
Byte[] bufferBytes = new byte[1024];
allDone.Set();
Socket client = (Socket) AR.AsyncState;
int x = client.Receive(bufferBytes);
Program.mainWin.console.Text += System.Text.Encoding.Default.GetString(bufferBytes);
}
public string GetLocalIPv4(NetworkInterfaceType _type)
{
string output = "";
foreach (NetworkInterface item in NetworkInterface.GetAllNetworkInterfaces())
{
if (item.NetworkInterfaceType == _type && item.OperationalStatus == OperationalStatus.Up)
{
foreach (UnicastIPAddressInformation ip in item.GetIPProperties().UnicastAddresses)
{
if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
{
output = ip.Address.ToString();
}
}
}
}
return output;
}
}
}
You're never calling EndAccept (from the example you linked):
// Get the socket that handles the client request.
Socket listener = (Socket) ar.AsyncState;
Socket handler = listener.EndAccept(ar); // This right here
The socket in ar.AsyncState is the listening socket, not the connected client. AsyncState is an arbitrary object you can use to pass information to the callback method (AcceptConnectionAsync). In this case, you are passing the serverSocket (the second parameter below):
serverSocket.BeginAccept(new AsyncCallback(AcceptConnectionAsync), serverSocket);
When you call EndAccept on the listening socket, you are getting a new Socket instance that is a specific connection to the client -- your listener socket will start the asynchronous request to accept another connection in your while loop in StartListen. The socket returned by EndAccept is in a connected state and ready to communicate with the other endpoint, based on this specific callback invocation (hence, the requirement to supply IAsyncResult as an argument).
This is referred to as the Asynchronous Programming Model. MSDN has some great information on this (as usual).

Detect SQL event with C# application

I have the code below (a literal copy/paste from MSDN website just to be clear), which seems to connect as it should (except for an "Access Denied" error which is okay because my security requests haven't gone through yet). What I need to do is detect when our sql server has executed an insert or update operation. Basically this application should be running 24/7 and perform certain functions when an operation as such comes across the listener. I'm not asking for the code to be laid out in front of me, but I am asking where to start. This is something I have no clue how to do at this point and am being told I have roughly a week to figure it out and get it done. Can someone point me in the right direction? Thank you in advance!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace Connect_Server
{
class Program
{
static string output = "";
static void Main(string[] args)
{
createListener();
}
static public void createListener()
{
// Create an instance of the TcpListener class.
TcpListener tcpListener = null;
IPAddress ipAddress = Dns.GetHostEntry("localhost").AddressList[0];
try
{
// Set the listener on the local IP address
// and specify the port.
tcpListener = new TcpListener(ipAddress, 80);
tcpListener.Start();
output = "Waiting for a connection...";
}
catch (Exception e)
{
output = "Error: " + e.ToString();
Console.Write(output);
}
while (true)
{
// Always use a Sleep call in a while(true) loop
// to avoid locking up your CPU.
Thread.Sleep(10);
// Create a TCP socket.
// If you ran this server on the desktop, you could use
// Socket socket = tcpListener.AcceptSocket()
// for greater flexibility.
TcpClient tcpClient = tcpListener.AcceptTcpClient();
// Read the data stream from the client.
byte[] bytes = new byte[256];
NetworkStream stream = tcpClient.GetStream();
stream.Read(bytes, 0, bytes.Length);
SocketHelper helper = new SocketHelper();
helper.processMsg(tcpClient, stream, bytes);
}
}
}
}
Check out SQL Server Notifications. This will send a signal to your app when some underlying dataset changes. I'm not sure how heavy this is for the server, so if you have a large number of clients waiting for a notification you should load-test it carefully....

TcpClient not connecting to remote server

I'm trying to connect to a remote machine using the TcpClient class, but it keeps failing:
An unhandled exception of type 'System.Net.Sockets.SocketException'
occurred in System.dll
Additional information: 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
Testing the code when the client and server are local works, but when I try connecting to a remote machine, it no longer works.
Here is the server code:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WebSocketServer
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Starting a new WebSockets server.");
WebSocketServer server = new WebSocketServer();
Console.WriteLine("The WebSocket server has started.");
bool userRequestedShutdown = false;
while (!userRequestedShutdown)
{
Console.ReadLine();
DialogResult result = MessageBox.Show("Do you want to shut the server down?", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
if (result == DialogResult.Yes)
{
userRequestedShutdown = true;
}
}
server.Stop();
}
class WebSocketServer
{
TcpListener server;
Thread connectionListener;
ConcurrentDictionary<TcpClient, Thread> clients = new ConcurrentDictionary<TcpClient, Thread>();
public WebSocketServer()
{
server = new TcpListener(IPAddress.Parse("127.0.0.1"), (int)Properties.Settings.Default["Port"]);
try
{
server.Start();
}
catch (Exception exception)
{
Console.WriteLine("Error while trying to start the server: {0}", exception.ToString());
}
connectionListener = new Thread(() =>
{
while (true)
{
Console.WriteLine("Waiting for a new client.");
try
{
TcpClient client = server.AcceptTcpClient();
Thread clientListener = new Thread(() =>
{
try
{
NetworkStream stream = client.GetStream();
byte[] buffer = new byte[1024];
Console.WriteLine("Wating for the client to write.");
while (client.Connected)
{
try
{
int bytesRead = stream.Read(buffer, 0, buffer.Length);
Console.WriteLine("Read {0} bytes from the client.", bytesRead);
string data = Encoding.UTF8.GetString(buffer).Substring(0, bytesRead);
Console.WriteLine("Read the following string from the client: {0}", data);
}
catch (Exception exception)
{
Console.WriteLine("Error while trying to read from a TCP client: {0}", exception.ToString());
break;
}
}
Console.WriteLine("Client disconnected. Removing client.");
}
catch (Exception exception)
{
Console.WriteLine("Error while trying to connect to a TCP client: {0}", exception.ToString());
}
client.Close();
clients.TryRemove(client, out clientListener);
});
clientListener.Start();
clients.TryAdd(client, clientListener);
}
catch (Exception exception)
{
Console.WriteLine("Error while trying to accept a TCP client: {0}", exception.ToString());
}
Console.WriteLine("A client has connected.");
}
});
connectionListener.Start();
}
public void Stop()
{
server.Stop();
connectionListener.Abort();
}
}
}
}
Here is the client code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace WebSocketClient
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Opening up a TcpClient.");
TcpClient client = new TcpClient();
client.Connect("<Remote Hostname>", <RemotePortNumber>);
Console.WriteLine("TcpClient has connected.");
NetworkStream stream = client.GetStream();
bool closed = false;
new Thread(() =>
{
while (!closed)
{
Console.WriteLine("Writing data to the stream.");
byte[] bytes = Encoding.UTF8.GetBytes("Hello, world.");
stream.Write(bytes, 0, bytes.Length);
Thread.Sleep(1000);
}
}).Start();
Console.ReadLine();
closed = true;
}
}
}
So what is the problem here? I am hosting the server on an Azure Virtual Machine, I have opened up the TCP port I am trying to use as the <RemotePortNumber> in Windows Firewall on my remote server by setting both inbound and outbound rules to allow all traffic in and out of the machine on that port, and I have created a TCP endpoint on my Azure portal that maps the external port of my Virtual Machine's hostname to the internal, private port, of my Virtual Machine, both set to map the same port number of <RemotePortNumber> for consistency. To connect, I am using a <Remote Hostname> value of <MyServiceName>.cloudapp.net. I have also tried connecting the stream by using IPAddress.Parse(<Public IP of my Azure Server>) but have had no luck...it just keeps timing out, as if I am not formatting the hostname correctly or something. What am I missing? If anyone can provide some clues as to how to debug the issue, that would also be very helpful.
Update: Running a WireShark trace, I see a lot of these messages (is this bad? I think the TCP Retransmission might be okay if we take into account that for Azure you have to route packets from the public domain's port to the private port of the VM, but not sure about whatever the RST, ACK's are):
Update: Running Microsoft Message Analyzer, I see these messages on the Local Link Layer:
Note: My VM has an Internal IP of 100.75.20.78 and a Public IP of 191.238.37.130. It has the public domain name of ovidius.cloudapp.net. I am trying to host the application on TCP port 6490. I blacked out my personal IP address for the sake of not giving it up.
I have mapped the TCP port in the Azure portal from domain to VM as follows:
After spending two mother _______ days on this (fill in the blanks), I got a little bit creative in ways of exploring alternative methods to try and see if I could rule routing issues out. I can pretty much safely conclude that Microsoft's Virtual Machine routing fails when you map a Public Port to the same Private Port.
For example, I tried setting up the new Socket endpoint below, and it worked because it didn't map the same domain port to the same Virtual Machine port like I had previously done with the WebSocketServer:
Update: Also, when hosting, I had to set up the server, not on the IP of 127.0.0.1, but the Internal IP, which in my case is 100.75.20.78.
Update Again: Contrary to the above solution, I tried to delete the old endpoint at 6490 and recreated it, and it seems to be working when I connect to that address now. I'm not entirely sure why, I can only say that the only difference here is that I had firewall rules on to allow that endpoint's port before creating the endpoint this time...not sure if that would make a difference. I'm honestly not sure what was causing the issues.
Update Yet Again: Just thought about it some more...I think it comes down to the following two issues:
You need to host the server on the Internal IP of your Azure Virtual Machine, not localhost or 127.0.0.1 like I was doing.
You need to not have the "ENABLE DIRECT SERVER RETURN" feature enabled on your Azure endpoint.

C# Client / Server Thread Connection

I am getting into trouble with this part of code.
In fact I want to set a Client/Server Application.
In the client part I launch a Thread which function is only to check everytime if it is connected to the server (if the connection to the server is still established)
TraceLog is a class that uses its Info() method to write in a file.
this is is the client code :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.IO;
namespace ClientApp
{
class ClientOpenConnection
{
private static Thread threadConnect;
static TcpClient myClient = new TcpClient();
static String host = "";
static Int32 port = 0;
//Function that makes the client runs
public static void RunClient(String hostname, Int32 hostport)
{
host = hostname;
port = hostport;
int _tryAgain = 0;
while (!myClient.Connected) {
try
{ //I start the connection
myClient.Connect(host, port);
}
catch {
}
_tryAgain += 10;
if (_tryAgain == 1000)
break;
//_tryAgain allows me to define how long will the client try to connect to the server.
}
TraceLog.Info("Out of the while ", ""); // This is to know where am I
if (_tryAgain != 1000)
{ //If I get out because _tryAgain is less than 1000. It means that I am already connected to the server
//Here I start a Thread to be sure that I am always connected to the server
threadConnect = new Thread(isConnected);
threadConnect.Start();
TraceLog.Info("Launch the thread","");
}
//While threadConnect is executing parallely I continue my program
}
private static void isConnected() {
//I keep my eyes on the network connection
while (myClient.Connected) {
//Nothing is done
}
TraceLog.Info("The connection has been lost","");
RunClient(host,port);
}
}
}
The problem that I am having, when I start the client before the server I enter the first WHILE loop. it is OK at this level.
and when I start the server after, I launch the threadConnect but the problem is that if now I stop the server, normally i should have inside the log file "The connection has been lost" but I have nothing.
What is wrong with this part of code?
Have you already done something like this in the past?
I come with a modification but still having problem to obtain what I want, ie the client still get trying to contact the server eveytime even if the server is stopped .
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.IO;
namespace ClientApp
{
class ClientOpenConnection
{
private static Thread threadConnect;
static TcpClient myClient = new TcpClient();
static String host = "";
static Int32 port = 0;
//Function that makes the client runs
public static void RunClient(String hostname, Int32 hostport)
{
host = hostname;
port = hostport;
TraceLog.Info(" -> "+myClient.Connected,"");
while (!myClient.Connected) {
try
{
myClient.Connect(host, port);
TraceLog.Info(" <-> " + myClient.Connected, "");
}
catch {
TraceLog.Info("Trying to contact the server","");
}
}
TraceLog.Info("I am connected ", "");
//Here I start a Thread to be sure that I am always connected to the server
threadConnect = new Thread(isConnected);
threadConnect.Start();
TraceLog.Info("Launch the thread to be sure I am constantly online","");
}
private static void isConnected() {
//I keep my eyes on the network connection
TraceLog.Info("->>"+myClient.Connected,"");
while (myClient.Connected) {
Thread.Sleep(500);
try
{
NetworkStream stream = myClient.GetStream();
ASCIIEncoding ascii = new ASCIIEncoding();
byte[] _incomingMsg = new byte[1024];
stream.Read(_incomingMsg, 0, _incomingMsg.Length);
String strToGet = System.Text.Encoding.ASCII.GetString(_incomingMsg);
strToGet = strToGet.Trim();
if (!strToGet.Equals("ONLINE"))
if (strToGet.Equals(""))
{
TraceLog.Info("The message receive is empty","");
break;
}
}
catch {
break;
}
}
TraceLog.Info("The connection has been lost", "");
RunClient(host, port);
}
}
}
But when I call the RunClient() in the isConnected() function it executes in the WHILE and output TraceLog.Info("Trying to contact the server",""); even if I start the server again, the client remains in the while loop and never connects at all.
From MSDN:
The Connected property gets the connection state of the Client socket
as of the last I/O operation. When it returns false, the Client socket
was either never connected, or is no longer connected.
Because the Connected property only reflects the state of the
connection as of the most recent operation, you should attempt to send
or receive a message to determine the current state. After the message
send fails, this property no longer returns true. Note that this
behavior is by design. You cannot reliably test the state of the
connection because, in the time between the test and a send/receive,
the connection could have been lost. Your code should assume the
socket is connected, and gracefully handle failed transmissions.
In other words, in order to check if you are still connected, you need to send or receive some data and then check the connection state.
Since your code doesn't send any packets after the connection is made, the connected property always returns true, and the loop never exits.

Categories

Resources