How to Close a TCP/IP Connection - c#

I wasn't taught networking very well. I know the basics of TCP/IP, but I'm facing an assignment where I have to manage multiple threads for multiple projects that communicate with each other in the same solution. I'm working in Window's Forms, C#, and for simplicity's sake I'll write only what needs to be written.
This is my Client class, which connects to the Server, handles messages to and from the server, and logs out from the server.
private TcpClient ClientConnection = null;
private NetworkStream CommandStream = null;
private Thread ClientThread = null;
bool isRunning = false;
public Client()
{
InitializeComponent();
try
{
//open the connection to the command port
ClientConnection = new TcpClient(address, Convert.ToInt32(port));
//Get the command stream
CommandStream = ClientConnection.GetStream();
if (CommandStream != null)
{
isConnected = true;
ClientThread = new Thread(Receive);
isRunning = true;
ClientThread.Start();
}
errorLabel.Visible = false;
}
catch (Exception ex)
{
errorLabel.Visible = true;
errorLabel.Text = "Failed to Connect";
}
}
private void Receive()
{
Byte[] data = new Byte[1024];
string message = string.Empty;
int BytesReceived = 0;
while (isRunning == true)
{
BytesReceived = CommandStream.Read(data, 0, 1024);
message = Encoding.ASCII.GetString(data, 0, BytesReceived);
//Do something with the message
}
}
private void logoutButton_Click(object sender, EventArgs e)
{
//Do logout logic here
errorLabel.Visible = false;
try
{
if (ClientConnection != null)
{
Byte[] command = new Byte[1024];
string commandStr = "SHUTDOWN";
command = Encoding.ASCII.GetBytes(commandStr);
CommandStream.Write(command, 0, command.GetLength(0));
ClientConnection.Close();
CommandStream.Close();
isRunning = false;
if (ClientThread.IsAlive == true)
{
errorLabel.Visible = true;
errorLabel.Text = "Thread still alive. Failed to Disconnect";
}
}
}
catch(Exception ex)
{
errorLabel.Visible = true;
errorLabel.Text = "Failed to Disconnect";
}
}
And this is my server class' Process Handler Function:
private void CommandProcessHandler(Socket client)
{
Byte[] data = new Byte[1024];
NetworkStream NetStream = null;
//Exception check
if(client.Connected == true)
NetStream = new NetworkStream(client);
while(bCommandListener == true)
{
//Read the command from the client
int bytes = NetStream.Read(data, 0, 1024);
string Command = Encoding.ASCII.GetString(data, 0, bytes);
//Do something with the command
if (Command == "SHUTDOWN")
{
NetStream.Close();
client.Close();
bCommandListener = false;
continue;
}
//Display the command in the command list box
string buttonPressed;
string buttonLetter;
buttonPressed = CommandDataObject.Instance.DecodeUIDFromMessage(Command);
buttonLetter = CommandDataObject.Instance.DecodeMessageFromUID(Command);
Command = ((client.RemoteEndPoint) as IPEndPoint).Address.ToString() + ">>>" + Command;
UpdateCommandsListBox(Command);
}
}
I'm sure that I'm starting up the threads perfectly fine, but the issue lies in shutting them down. This was an aspect I was never properly taught, and am having trouble learning. As it stands, I press the "log out" button, which should send a message to the server to shutdown, as well as close the TcpClient and NetworkStream. It also sets the isRunning bool, which keeps the client's Receive thread active, to false.
However, as it stands, I keep getting an error when I do this, on line 98 (during the client's Receive function, when BytesReceived = CommandStream.Read) as follows:
An unhandled exception of type 'System.IO.IOException' occurred in System.dll
Additional information: Unable to read data from the transport connection: A blocking operation was interrupted by a call to WSACancelBlockingCall.
I'm not sure what the error is referring to, but I've been stuck on this for a while and want to get it fixed. Any solutions?

When you use NetworkStream, it will throw an IOException if the underlying socket is closed while trying to read, see MSDN documentation . So your code is perfectly fine. You just have to handle the exception.
If you were to read the socket directly, you would just receive 0 when the socket is closed.

Related

C# read bluetooth stream reliably (InTheHand 32feet)

I have a problem with reliably read a bluetooth stream.
It's the first time I worked with bluetooth connections.
The application communicates with a Arduino over a bluetooth module.
It will send a command and get a response.
For example, the response should look something like this:
100,200,300,400
This is what I get:
1
and if I get another response (also if it should look completely different) I get rest of the response requested before:
00,200,300,400
Sometimes I even get an empty response.
Here is the code I use to read and write to the stream:
void BluetoothClientConnectCallback(IAsyncResult result)
{
try
{
BluetoothClient client = (BluetoothClient)result.AsyncState;
client.EndConnect(result);
NetworkStream stream = client.GetStream();
stream.ReadTimeout = 1000;
_frm.printMsg("Connected!", false);
byte[] receive = new byte[1024];
while (true)
{
while (!ready) ;
if (stopConnection == true)
{
return;
}
try
{
stream.Write(message, 0, message.Length);
}
catch
{
_frm.printMsg("Error occurred while writing stream.", true);
}
try
{
if (Commands.awaitresponse == true)
{
Array.Clear(receive, 0, receive.Length);
readMessage = "";
do
{
stream.Read(receive, 0, receive.Length);
readMessage += Encoding.ASCII.GetString(receive);
}
while (stream.DataAvailable);
_frm.printMsg("Received: " + readMessage, false);
Commands.awaitresponse = false;
}
}
catch
{
_frm.printMsg("Error occurred while receiving stream.", true);
}
ready = false;
}
}
catch
{
_frm.printMsg("Error occurred while connecting.", true);
}
}
I was looking a while into it, but couldn't come to a solution.
After some more debugging and testing I came to a solution by myself.
I added 1 secound of delay Thread.Sleep(1000); before reading the stream.
All packages are now red correctly.

Client Server File Transfer, FIN ACK received right after the connection is established

I am having a hard time figuring this out, so any help would be much appreciated.
I'm trying to implement a client/server file transfer software suite between a web server (MS Azure) and some embedded systems running on Windows Embedded Standard. On the web server side I have the Client application(Web APP + ASMX WebService), and on each embedded system I have a server application (Winforms app) listening on port 8020, as illustrated on the following figure.
system architecture diagram
My local testing environment consists of my dev pc (Windows 10, VS2015, 192.168.1.2, hosting both Web APP and the WebService) and two robots all connected to our local LAN (Robot Client 1 : 192.168.1.80, Robot Client 2 : 192.168.1.132)
Locally, everything works perfectly. the file transfer is completed successfully. This is, however, not the case, once I deploy both web app and webservice to our MS Azure Web server. I used wireshark to monitor the traffic and see exactly what was going on. As you can see from the attached figure. the client application installed on the server sends [FIN, ACK] right after the connection is established?!
Wireshark capture
I have added the corresponding endpoint on the Virtual Machine.I also have the port 8020 open on my router locally and I have created an inbound rule on the same port on each firewall on both robots.
As to the code,
WebApplication :
private void TrasnferMAJ(string RobotsRef, string SelectedTime, string robotName, string Vmaj)
{
WebserviceRobots ws = new WebserviceRobots();
ws.SendMAJCompleted += new SendMAJCompletedEventHandler(SendMAJCompleted);
ws.SendMAJAsync(RobotsRef, "", robotName, Vmaj);
ws.SendMAJ(RobotsRef, "", robotName, Vmaj);
}
private void SendMAJCompleted(object sender, SendMAJCompletedEventArgs e)
{
string UpdateStatus = "";
if (e != null)
UpdateStatus = e.Result;
}
Web Service :
[WebMethod]
public string SendMAJ(string RobotsRef, string SelectedTime, string robotName, string Vmaj)
{
int port = 8020;
string message = "Envoi terminé avec succès"; // Transfer completed successfully
byte[] SendingBuffer = null;
TcpClient client = null;
NetworkStream netstream = null;
try
{
client = new TcpClient(robotName, port); // initiate comm
netstream = client.GetStream(); // Network stream to be used
FileStream Fs = new FileStream(GetMajPath(Vmaj), FileMode.Open, FileAccess.Read);
int NoOfPackets = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(Fs.Length) / Convert.ToDouble(BufferSize))); // the number of packets to be sent
int TotalLength = (int)Fs.Length, CurrentPacketLength = 0; // initializing TotalLength to stream length (nbr of bytes)
for (int i = 0; i < NoOfPackets; i++)
{
if (TotalLength > BufferSize) // if we still have more than one Kbytes
{
CurrentPacketLength = BufferSize;
TotalLength = TotalLength - CurrentPacketLength; // totalLength : the amount of data that has not been sent yet
}
else
CurrentPacketLength = TotalLength; // this here could be less than a byte.
SendingBuffer = new byte[CurrentPacketLength];
Fs.Read(SendingBuffer, 0, CurrentPacketLength); // reading the data from the filestream, & writing it to the SendingBuffer
netstream.Write(SendingBuffer, 0, (int)SendingBuffer.Length); // Writing the SendingBuffer Buffer to the network stream
}
Fs.Close();
}
catch (Exception ex)
{
message = ex.Message;
}
finally
{
netstream.Close();
client.Close();
}
// if it all goes well, the message should be ="Envoi terminé avec succès",else it would be assigned the exception message.
return message;
}
The Server application (WinForms) :
public partial class ReceiveMAJs : Form
{
private const int BufferSize = 1024;
public string Status = string.Empty;
public Thread T = null;
public ReceiveMAJs()
{
InitializeComponent();
}
private void ReceiveMAJs_Load(object sender, EventArgs e)
{
label1.Text = "Serveur en cours d'exécution...";
// Creating a seperate thread for recieving the MAJ file
ThreadStart Ts = new ThreadStart(StartReceiving);
T = new Thread(Ts);
T.Start();
}
public void StartReceiving()
{
ReceiveTCP(8020);
}
public void ReceiveTCP(int portN)
{
TcpListener Listener = null;
try
{
Listener = new TcpListener(IPAddress.Any, portN);
Listener.Start();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
byte[] RecData = new byte[BufferSize];
int RecBytes;
for (;;)
{
TcpClient client = null;
NetworkStream netstream = null;
Status = string.Empty;
try
{
string message = "Mettre à jour ";
string caption = "Connexion entrante";
MessageBoxButtons buttons = MessageBoxButtons.YesNo;
DialogResult result;
if (Listener.Pending()) // true if there are any pending connections
{
client = Listener.AcceptTcpClient();
netstream = client.GetStream();
Status = "Connecter au serveur des MAJs\n";
result = MessageBox.Show(message, caption, buttons);
if (result == DialogResult.Yes)
{
string SaveFileName = string.Empty;
SaveFileDialog DialogSave = new SaveFileDialog();
DialogSave.Filter = "Tous les fichiers (*.*)|*.*";
DialogSave.RestoreDirectory = true;
DialogSave.Title = "L'emplacement de sauvegarde?";
DialogSave.InitialDirectory = #"C:/";
Invoke((Action)(() => {
if (DialogSave.ShowDialog() == DialogResult.OK)
SaveFileName = DialogSave.FileName;
}));
if (SaveFileName != string.Empty)
{
int totalrecbytes = 0;
FileStream Fs = new FileStream(SaveFileName, FileMode.OpenOrCreate, FileAccess.Write);
while ((RecBytes = netstream.Read(RecData, 0, RecData.Length)) > 0)
{
Fs.Write(RecData, 0, RecBytes);
totalrecbytes += RecBytes;
}
Fs.Close();
}
netstream.Close();
client.Close();
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
Thread.Sleep(5); // avoiding overworking the processor
}
}
private void btnExit_Click(object sender, EventArgs e)
{
T.Abort();
this.Close();
}
}
Thank you for your answers.

C# client socket multiple send and receive

I am using sockets for TCP-IP connection and I would like to establish simple system send-receive from the client side.
Socket sck;
sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint localEndpt = new IPEndPoint(IPAddress.Parse("123.123.123.1"), 12345);
try
{
sck.Connect(localEndpt);
}
catch
{
Console.Write("Unable to Connect");
}
while (true)
{
Console.WriteLine("Enter Text");
string sendtext = Console.ReadLine();
byte[] Data = Encoding.ASCII.GetBytes(sendtext);
sck.Send(Data);
Console.WriteLine("Data Sent!");
byte[] bytesReceived = new byte[sck.ReceiveBufferSize];
int bytes = 0;
String strReceived = "";
int dataAvailable = 0;
while (dataAvailable == 0 || dataAvailable != sck.Available)
{
dataAvailable = sck.Available;
Thread.Sleep(100); // if no new data after 100ms assume transmission finished
}
if (sck.Available > 0)
{
bytes = sck.Receive(bytesReceived, bytesReceived.Length, 0);
strReceived+=Encoding.ASCII.GetString(bytesReceived, 0, bytes);
}
Console.WriteLine("Received from server: " + strReceived);
}
Console.Read();
The problem is that first requests goes throught but the second does not, because socket is not available anymore (socket "Availabe" attribute value is 0). What am I doing wrong? What would be the easiest way to establish multiple send-recieve requests (in order)?
This code works fine for me
private List<Socket> _clients = new List<Socket>();
private Thread _dataReceiveThread;
private bool _isConnected;
private void DataReceive()
{
while (_isConnected)
{
List<Socket> clients = new List<Socket>(_clients);
foreach (Socket client in clients)
{
try
{
if (!client.Connected) continue;
string txt = "";
while (client.Available > 0)
{
byte[] bytes = new byte[client.ReceiveBufferSize];
int byteRec = client.Receive(bytes);
if (byteRec > 0)
txt += Encoding.UTF8.GetString(bytes, 0, byteRec);
}
if (!string.IsNullOrEmpty(txt))
/* TODO: access the text received with "txt" */
}
catch (Exception e)
{
Exception_Handler(e);
}
}
}
}
Just run this code to get started
_isConnected = true;
_dataReceiveThread = new Thread(DataReceive);
_dataReceiveThread.Start();
Update list box in Cross thread:
This code can be placed in the comment section.
myListBox1.Invoke((Action)(() => { myListBox1.Items.Add(txt) }));
Socket. Available does NOT indicate whether the socket is available, but incoming data is available for reading:
https://msdn.microsoft.com/en-us/library/ee425135.aspx
Your program quits because it checks for a reply (incoming data) immediately after sending a message out. Use a Thread.Sleep before checking for data.
Maybe the message has not even been sent, because Socket.Send just places it in the network interface card's output buffer. When the socket finally sends the message, it will upare the connection state. If it got no reply (on a TCP connection), it will tell you that it is disconnected when you query the state. On UDP it will tell you nothing, because UDP is connectionless.

C# TcpClient "The operation is not allowed on non-connected sockets."

My goal is to create a TcpClient that stays connected, allowing messages to be sent to the server, as well as having a timed monitor that sends a special message to the server during a certain idle frequency. Haven't made it too far before getting stumped.
With the current code, the first message sent using a console tester app receives fine, but upon sending another an exception is thrown with the message "The operation is not allowed on non-connected sockets."
I have tried removing the stream.Dispose() line and it will hang on stream.Read(...) during the second attempt. I have also tried making NetworkStream stream a member of the class and set it to client.GetStream() in the constructor and it will hang on stream.Read(...) during the second attempt.
public class TcpClientTest
{
private TcpClient client = new TcpClient();
private string hostName;
private int port;
public TcpClientTest(string hostName, int port)
{
this.hostName = hostName;
this.port = port;
client.Connect(hostName, port);
}
public byte[] SendMessage(string name, string message)
{
if (client == null) throw new Exception("Client connection has not been established");
Person person = new Person();
person.Name = name; person.Message = message;
byte[] messageBytes = (System.Text.Encoding.Unicode.GetBytes(Newtonsoft.Json.JsonConvert.SerializeObject(person)));
const int bytesize = 1024 * 1024;
try
{
NetworkStream stream = client.GetStream();
if (stream != null)
{
stream.Write(messageBytes, 0, messageBytes.Length); // Write the bytes
messageBytes = new byte[bytesize]; // Clear the message
// Receive the stream of bytes
stream.Read(messageBytes, 0, messageBytes.Length);
}
// Clean up
stream.Flush();
stream.Dispose();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return messageBytes; // Return response
}
}
// In console tester app
static void Main(string[] args)
{
TcpClientTest client = new TcpClientTest("127.0.0.1", 1234);
string exit = "2";
do
{
if (exit == "1") client.SendMessage("TEST", "TEST");
Console.WriteLine("1 Send Message 2 Exit");
exit = Console.ReadLine();
} while (exit != "2");
}

How do I make TcpClient stop in a thread?

I've a thread that runs following tcpConnect method. I wish to stop it at any given time by setting Program.PrepareExit to true. However my program is stuck at:
Int32 bytes = stream.Read(data, 0, data.Length); and doesn't really react to Program.PrepareExit set to true. How can i make it to always quit when I tell it so?
public static readonly Thread MyThreadTcpClient = new Thread(ThreadTcpClient);
private static void ThreadTcpClient() {
Connections.tcpConnect(ClientTcpIp, ClientTcpPort);
}
public static void Main() {
MyThreadTcpClient.Start();
.... some code....
Program.PrepareExit = true;
}
public static bool tcpConnect(string varClientIp, int varClientPort) {
var client = new TcpClient();
try {
client = new TcpClient(varClientIp, varClientPort) {NoDelay = true};
NetworkStream stream = client.GetStream();
var data = new Byte[256];
while (!Program.PrepareExit) {
Int32 bytes = stream.Read(data, 0, data.Length);
string varReadData = Encoding.ASCII.GetString(data, 0, bytes);
if (varReadData != "" && varReadData != "echo") {
VerificationQueue.EnqueueRelease(varReadData);
}
}
} catch (ArgumentNullException e) {
MessageBox.Show(e.ToString(), "ArgumentNullException");
tcpConnect(varClientIp, varClientPort);
} catch (SocketException e) {
MessageBox.Show(e.ToString(), "SocketException");
tcpConnect(varClientIp, varClientPort);
} catch (IOException e) {
if (e.ToString() != "Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.") {
}
MessageBox.Show(e.ToString());
tcpConnect(varClientIp, varClientPort);
} finally {
client.Close();
}
return false;
}
Three options suggest themselves:
Make the thread a daemon (background) thread. The process will exit when the only live threads are daemon threads
Set a timeout on the read call, possibly having to change to use the underlying socket API. That won't be pretty, to be honest.
Use asynchronous IO. Also a bit of a pain.
Do you need this thread to do anything in terms of an orderly shutdown? If not, the daemon thread approach would probably be simplest.

Categories