This is a TCP Program which receives data from a TCP connection, then parse it and transfer it to another TCP connection. When I exit application, it doesn't work. It will remain as a process in the system.
As I am not a very experienced developer, can someone please help me to find the error in this code..
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
namespace Machine_Feeder
{
public partial class FeederControlMonitor : Form
{
TcpListener Listener = null;
public string Status = string.Empty;
public Thread T = null;
public FeederControlMonitor()
{
InitializeComponent();
}
private void FeederControlMonitor_Load(object sender, EventArgs e)
{
txtStatus.Text = "Feeder waiting for data...";
ThreadStart Ts = new ThreadStart(StartReceiving);
T = new Thread(Ts);
T.Start();
}
public void StartReceiving()
{
ReceiveTCP(9100);
}
public void ReceiveTCP(int portN)
{
try
{
Listener = new TcpListener(IPAddress.Any, portN);
Listener.Start();
}
catch (Exception ex)
{
File.WriteAllText(#"C:\\Drive\\ex.txt", ex.Message);
Console.WriteLine(ex.Message);
}
try
{
while (true)
{
Socket client = Listener.AcceptSocket();
var childSocketThread = new Thread(() =>
{
byte[] data = new byte[10000];
int size = client.Receive(data);
ParseData(System.Text.Encoding.Default.GetString(data));
client.Close();
});
childSocketThread.Start();
}
Listener.Stop();
}
catch (Exception ex)
{
File.WriteAllText(#"C:\\Drive\\ex.txt", ex.Message);
}
}
public void ParseData(string data)
{
var useFulData = data.Substring(data.IndexOf("F1")).Replace(" ", " ");// Space
useFulData = useFulData.Remove(useFulData.IndexOf("<ETX>"));
string[] delimeters = { "<DEL>", "<ESC>" };
var listOfValues = useFulData.Split(delimeters, StringSplitOptions.None).ToList();
int pos = 0;
for (int i = 1; i < listOfValues.Count; i += 2, pos++)
{
listOfValues[pos] = listOfValues[i];
}
listOfValues.RemoveRange(pos, listOfValues.Count - pos);
txtHealthCard.Invoke((Action)delegate { txtHealthCard.Text = listOfValues[0]; });
txtCID.Invoke((Action)delegate { txtCID.Text = listOfValues[1]; });
txtMedicalFitLocation.Invoke((Action)delegate { txtMedicalFitLocation.Text = listOfValues[2]; });
txtGender.Invoke((Action)delegate { txtGender.Text = listOfValues[3]; });
txtAge.Invoke((Action)delegate { txtAge.Text = listOfValues[4]; });
txtPatientName.Invoke((Action)delegate { txtPatientName.Text = listOfValues[5]; });
MyProtocolMaker(listOfValues[5],
listOfValues[4],
listOfValues[2],
listOfValues[3],
listOfValues[8],
listOfValues[1],
listOfValues[10],
);
}
private void btnExit_Click(object sender, EventArgs e)
{
Listener.Stop();
T.Abort();
this.Close();
}
private void MyProtocolMaker(
string patientName,
string patientAge,
string mfitLocation,
string gender,
string healthCardNo,
)
{
string feederInfo = "^^^P^PI" + healthCardNo + "^PN" + patientName + "^PA" + patientAge + "^PS" + gender + "^P7" + mfitLocation +"^_SS^^^_S";
System.Net.Sockets.TcpClient clientSocket = new System.Net.Sockets.TcpClient("127.0.0.1", 8001);
NetworkStream serverStream = clientSocket.GetStream();
byte[] outStream = System.Text.Encoding.ASCII.GetBytes(feederInfo);
serverStream.Write(outStream, 0, outStream.Length);
serverStream.Flush();
serverStream.Close();
clientSocket.Close();
}
private void FeederControlMonitor_FormClosing(object sender, FormClosingEventArgs e)
{
Listener.Stop();
T.Abort();
this.Close();
}
}
}
You problem is, that you are creating threads within the thread. These threads are keeping the application alive. Try marking them as background threads: (This is red-tape solution)
var childSocketThread = new Thread(() =>
{
byte[] data = new byte[10000];
int size = client.Receive(data); // <-- the thread hangs on these and will block termination
ParseData(System.Text.Encoding.Default.GetString(data));
client.Close();
});
childSocketThread.IsBackground = true; // <---
childSocketThread.Start();
When thread are not marked as background (default), they will block application termination. You should create a list to store the client threads, so you can exit those threads nicely.
You should never abort a thread, unless there is no other way. Instead of aborting, you should exit the while loop in the thread.
As nice way is using a ManualResetEvent:
fields:
private ManualResetEvent _terminating = new ManualResetEvent(false);
in thread:
while (_terminating.WaitOne(0))
{
// thread code
}
on exit:
_terminating.Set();
T.Join();
Sidenote: TCP is streaming, so just reading 10k of bytes ones, does not guarantee a complete packet.
Related
New to WinForms but not ASP.NET or C#. Trying to make client/server app. Successfully received data from client on server but having troubles displaying it on server program winform. Codes are:
Server App code:
using System;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
namespace Server_App
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
IPEndPoint ep = new IPEndPoint(IPAddress.Loopback, 1234); //configure host
TcpListenerEx listener = new TcpListenerEx(ep); //set host to listen
if (!listener.Active)
{
listener.Start();
}
while (true)
{
const int byteSize = 1024 * 1024;
byte[] message = new byte[byteSize];
var s = listener.AcceptTcpClient();
s.GetStream().Read(message, 0, byteSize); //obtaining network stream and receiving data through .Read()
message = cleanMessage(message);
string g = System.Text.Encoding.UTF8.GetString(message);
addMessage(g);
}
}
private void addMessage(string m)
{
this.textBox1.Text = textBox1.Text + Environment.NewLine + " >> " + m;
}
private byte[] cleanMessage(byte[] rawMessageByte)
{
byte[] cleanMessage = rawMessageByte.Where(b => b != 0).ToArray();
return cleanMessage;
}
}
}
Client App code:
using System;
using System.Net.Sockets;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ClientApp
{
public partial class ClientApp : Form
{
public ClientApp()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var message = System.Text.Encoding.UTF8.GetBytes(txtFromClient.Text);
using (var client = new TcpClient("127.0.0.1", 1234))//make connection with the host
{
NetworkStream stream = client.GetStream();/*obtain network stream*/
stream.Write(message, 0, message.Length);
}
}
private void textBox1_Click(object sender, EventArgs e)
{
txtFromClient.Text = "";
}
}
}
Everything is happening as planned except for displaying received data on server program's Form1's textbox. On debugging, I confirmed the correct value received in variable m of line this.textBox1.Text = textBox1.Text + Environment.NewLine + " >> " + m;. Only problem is that this value cannot be displayed and hence seen on the Form1 of server program.
With the help and guidance from #AdrianoRepetti, solution to the given problem was furnished through the following code:
using System;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Linq;
namespace Server_App
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
backgroundWorker1.WorkerReportsProgress = true;
}
private void button1_Click(object sender, EventArgs e)
{
IPEndPoint ep = new IPEndPoint(IPAddress.Loopback, 1234); //configure host
if(!backgroundWorker1.IsBusy)
{
backgroundWorker1.RunWorkerAsync(ep); //called to start a process on the worker thread and send argument (listener) to our workerprocess.
}
}
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
IPEndPoint ep = e.Argument as IPEndPoint;
TcpListenerEx listener = new TcpListenerEx(ep);
if (!listener.Active)
{
listener.Start();
}
while (true)
{
try
{
const int byteSize = 1024 * 1024;
byte[] message = new byte[byteSize];
using (var s = listener.AcceptTcpClient())
{
s.GetStream().Read(message, 0, byteSize);//obtaining network stream and receiving data through .Read()
message = cleanMessage(message);
string g = System.Text.Encoding.UTF8.GetString(message);
backgroundWorker1.ReportProgress(0, g);
}
}
catch (Exception ex)
{
backgroundWorker1.ReportProgress(0, ex.Message);
}
finally
{
listener.Stop();
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
textBox1.AppendText(Environment.NewLine + ">> " + e.UserState);
}
private byte[] cleanMessage(byte[] rawMessageByte)
{
byte[] cleanMessage = rawMessageByte.Where(b => b != 0).ToArray();
return cleanMessage;
}
}
}
Hope it helps.
This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 6 years ago.
In the below code, I am getting null reference exception I didn't understand why I am getting that. Please help me to solve it.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Data.SqlClient;
using System.Configuration;
namespace TCPListener
{
public partial class Form1 : Form
{
// Declare our worker thread
private Thread workerThread = null;
public Form1()
{
InitializeComponent();
// Initialise and start worker thread
this.workerThread = new Thread(new ThreadStart(this.ReceiveTcpData));
this.workerThread.Start();
}
public void timer1_Tick(object sender, EventArgs e)
{
}
public TcpListener server = null;
public Int32 port = Convert.ToInt32(ConfigurationManager.AppSettings["PUERTO"].ToString());
public IPAddress localAddr = IPAddress.Parse(ConfigurationManager.AppSettings["IP"].ToString());
public void OpenSocket()
{
try
{
// TcpListener server = new TcpListener(port);
server = new TcpListener(localAddr, port);
// Start listening for client requests.
server.Start();
}
catch (SocketException e)
{
Common.CommonControls.writeToLogFile("SOCKET ERROR: " + e.Message);
}
finally
{
Common.CommonControls.writeToLogFile("INICIO DE ESCUCHA EN " + DateTime.Now);
}
}
private void ReceiveTcpData()
{
//Instancio los objetos
Entities.Program oPosiciones = new Entities.Program();
DataAccess.Program oPosicionesDA = new DataAccess.Program();
try
{
// Buffer for reading data
Byte[] bytes = new Byte[256];
String data = null;
// Enter the listening loop.
// Perform a blocking call to accept requests.
// You could also user server.AcceptSocket() here.
//TcpClient client = server.AcceptTcpClient();
TcpClient cliente = new TcpClient();
try
{
cliente = server.AcceptTcpClient();
}
catch (Exception e) { MessageBox.Show(e.ToString()); }
data = null;
// Get a stream object for reading and writing
NetworkStream stream = cliente.GetStream();
int i;
// Loop to receive all the data sent by the client.
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);
// Process the data sent by the client.
data = data.ToUpper();
if (data.Substring(0, 2) == "##")
{
//SalidaMonitor("Paquete recibido: LOGON REQUEST del equipo");
cliente.Close();
this.workerThread.Interrupt();
return;
}
byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);
//Show data on monitor
SalidaMonitor("Paquete recibido " + DateTime.Now + ": " + data);
//Declare entities
oPosiciones.Paquete = data;
//Database action
oPosicionesDA.InsertarPosiciones(oPosiciones);
// Send back a response.
//stream.Write(msg, 0, msg.Length);
//SalidaMonitor("Paquete enviado: " + msg);
}
// Shutdown and end connection
cliente.Close();
}
catch (SocketException e)
{
Common.CommonControls.writeToLogFile("SOCKET ERROR: " + e.Message);
}
catch (SqlException x)
{
Common.CommonControls.writeToLogFile("SQL ERROR: " + x.Message);
}
catch (Exception y)
{
Common.CommonControls.writeToLogFile("ERROR: " + y.Message);
}
finally
{
oPosiciones = null;
oPosicionesDA = null;
this.workerThread.Interrupt();
}
}
private void SalidaMonitor(string data)
{
lstMensajes.Invoke(new MethodInvoker(delegate { lstMensajes.Items.Add(data.ToString()); }));
lstMensajes.Invoke(new MethodInvoker(delegate { lstMensajes.SelectedIndex = lstMensajes.Items.Count - 1; lstMensajes.SelectedIndex = -1; }));
}
private void Form1_Load(object sender, EventArgs e)
{
OpenSocket();
}
private void Form1_Close(object sender, FormClosingEventArgs e)
{
server.Stop();
}
}
}
In the above code, I am getting error at cliente = server.AcceptTcpClient();. I don't understand why it's happening. If you need any information, let me know. Thanks
The Problem
in the constructor of the form you are creating and starting new Thread.
and this thread will call the ReceiveTcpData method, which user the server variable (and at this point this variable was not initialized yet) WHY??
because the server variable is initialized in the Form_Load which call the OpenSocket method to initalize the server variable. The most important part is The Form_Load method is called AFTER the constructor of the form.
In other words, the Thread is using the server variable before you initialize it.
The Solution
use the following constructor, and remove the Form_Load event handler
public Form1()
{
InitializeComponent();
// add this line.
OpenSocket();
// Initialise and start worker thread
this.workerThread = new Thread(new ThreadStart(this.ReceiveTcpData));
this.workerThread.Start();
}
Update
For the person who prefer to do everything in the Form_Load
here is another solution
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// add this line.
OpenSocket();
// Initialise and start worker thread
this.workerThread = new Thread(new ThreadStart(this.ReceiveTcpData));
this.workerThread.Start();
}
Well, if it is in that line, it is because server is not initialized.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
Hey guys I am new at the subject of Sockets
and I really need you help.
I am doing system of server and clients (like chat)
but something diffrent, I am doing it with Windows Form Application
in my server : I have list of sockets of all pepole that connect to the server, that already get acception from the server.
And I wanna to do a Timer that every X seconds it will runs on my List and check if the person is still connection I mean in that , that the person still connect on the internet and still can get packages and if not to remove him from the list.
someone can help me in c# how do it??
now at the server if someone is Exit the program Or if the internet is logout how i can check if the Client is out
and if yes so Close his connection?
i Read about TimeOut but how use it??? if it usfull?
Server:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Server
{
public partial class Form1 : Form
{
Socket sck;
static List<Socket> acc;
static List<Thread> thr;
//List<UserAt> thr;
static int port = 9000;
static IPAddress ip;
static Thread NewCon;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
acc = new List<Socket>();
//thr = new List<UserAt>();
thr = new List<Thread>();
NewCon = new Thread(getNewConnection);
//Console.WriteLine("please enter your host port ");
string inputPort = "9000";
try
{
port = Convert.ToInt32(inputPort);
}
catch
{
port = 9000;
}
ip = IPAddress.Parse("127.0.0.1");
sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sck.Bind(new IPEndPoint(ip, port));
sck.Listen(0);
NewCon.Start();
}
/// <summary>
/// get new connection from client
/// </summary>
public void getNewConnection()
{
while (true)
{
acc.Add(sck.Accept());
var t = new Thread(() => ReciveMessage(acc.Count-1));
t.Start();
thr.Add(t);
/* UserAt a = new UserAt();
a.index = acc.Count - 1;
a.thread = new Thread(() => ReciveMessage(a.index));
a.thread.Start();
thr.Add(a);
* */
}
}
public void ReciveMessage(int index)
{
while (true)
{
try
{
Thread.Sleep(500);
byte[] Buffer = new byte[255];
int rec = acc[index].Receive(Buffer, 0, Buffer.Length, 0);
Array.Resize(ref Buffer, rec);
//MessageBox.Show(Encoding.Default.GetString(Buffer));
//listBox1.Items.Add(Encoding.Default.GetString(Buffer));
SetText(Encoding.Default.GetString(Buffer));
}
catch
{
// thr[index].thread.Abort();
/*thr.RemoveAt(index);
for (int i = index+1; i < thr.Count;i++ )
{
thr[i].index -= 1;
}*/
break;
}
}
}
delegate void SetTextCallback(string text);
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.listBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.listBox1.Items.Add(text);
}
}
public string getIp()
{
IPHostEntry host;
string localIP = "?";
host = Dns.GetHostEntry(Dns.GetHostName());
foreach (IPAddress ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
localIP = ip.ToString();
}
}
return localIP;
}
}
}
Client
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Client
{
public partial class Form1 : Form
{
static string name = "";
static int port = 9000;
static IPAddress ip;
static Socket sck;
public Form1()
{
InitializeComponent();
}
public void ReciveMessage()
{
while (true)
{
Thread.Sleep(500);
byte[] Buffer = new byte[255];
int rec = sck.Receive(Buffer, 0, Buffer.Length, 0);
Array.Resize(ref Buffer, rec);
SetText(Encoding.Default.GetString(Buffer));
//MyChat.Items.Add(Encoding.Default.GetString(Buffer));
}
}
delegate void SetTextCallback(string text);
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.MyChat.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.MyChat.Items.Add(text);
}
}
private void Login_Click(object sender, EventArgs e)
{
name = UserName.Text;
ip = IPAddress.Parse("127.0.0.1");
string inputPort = "9000";
try
{
port = Convert.ToInt32(inputPort);
}
catch
{
port = 9000;
}
try
{
sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sck.Connect(new IPEndPoint(ip, port));
ReciveMes.Enabled = true;
byte[] conmsg = Encoding.Default.GetBytes("<" + name + ">" + " connected");
sck.Send(conmsg, 0, conmsg.Length, 0);
SendToServer.Enabled = true;
}
catch
{
MessageBox.Show("חיבור נכשל");
}
}
private void SendToServer_Click(object sender, EventArgs e)
{
byte[] sdata = Encoding.Default.GetBytes("<" + name + ">" + MyMessage.Text);
sck.Send(sdata, sdata.Length, 0);
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if(SendToServer.Enabled)
{
byte[] sdata = Encoding.Default.GetBytes("<" + name + ">" + "Is Quit");
sck.Send(sdata, sdata.Length, 0);
}
}
}
}
I am trying to build a chat, basically i used the invoke function what a thread.
I am able to read what the server sends me, but i am able to write only once. i am trying to finish this but not sure how to write to server each time the server:
(take into account that i wrote this before in console application form and the server works fine... i.e. the problem isnt with the server).
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Button btn1 = new Button();
btn1.Click += button1_Click;
}
StreamReader sr;
StreamWriter sw;
TcpClient connection;
private void Form1_Load(object sender, EventArgs e)
{
connection = new TcpClient("127.0.0.1", 5000);
sr = new StreamReader(connection.GetStream());
sw = new StreamWriter(connection.GetStream());
}
private void button2_Click(object sender, EventArgs e)
{
Thread t2 = new Thread(Reader);
t2.Start(connection);
}
string msg;
public void Reader(object o)
{
TcpClient con = o as TcpClient;
if (con == null)
return;
while (true)
{
msg = sr.ReadLine();
Invoke(new Action(Output));
}
}
public void Output()
{
ChatScreen.Text = msg;//set the message on the screen
}
string textinput;
private void button1_Click(object sender, EventArgs e)
{
textinput = InputLine.Text;
sw.WriteLine(textinput);// this thing, writes once, multiple clicks wont send a new line to the server :(..the problem is in this button
sw.Flush();
}
}
what I thought to do is to connect the button so it will be able to do multiple clicks ..e.g btn.Click()..or run a thread with invoke on the WriteLine (but my intuition says that making the button click several times would make the program work
You need to stop the thread process when you close the form, if not when you try to do the invoke, it will fail because the form is disposed and it can't be used to do an invoke. You can override the dispose method to stop the reader thread or you can do it on the onclose method. Or you can check on the reader process if the control it's available (it is not disposed) and if it's not available finish the read process.
You should prevent that the reader process will be launch multiple times too, to prevent errors, so you need to disable the button when the thread is run.
Edited:
You can use something like the following code to read multiple lines and to stop the thread when you close the form.
private bool mbIsRunning = true;
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
lock (this)
{
mbIsRunning= false;
}
}
private bool IsRunning
{
get
{
lock(this)
{
return mbIsRunning;
}
}
}
string msg;
public void Reader(object o)
{
TcpClient con = o as TcpClient;
if (con == null)
return;
while (IsRunning)
{
msg = reader.ReadLine();
string line;
while( (line = reader.ReadLine()) != null )
{
msg = msg + Enviroment.NewLine + line;
}
Invoke(new Action(Output));
}
}
Running up your code, I get a bunch of errors - from the TcpClient throwing an exception and so on.
However, assuming that you haven't posted all of your code, I would recommend putting a try...catch around all of your functions, and then breakpoints in the catch to see what the problem is. Examine the exceptions - exceptions should only be thrown in exceptional circumstances - so your code should really work without doing that.
I do concat on my server code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
TcpListener server = new TcpListener(IPAddress.Any, 5000);
server.Start();
Console.WriteLine("Server started");
string word = "";
savedObject saved = new savedObject();
while (true)
{
TcpClient connection = server.AcceptTcpClient();
Console.WriteLine("connection accepted");
ThreadPool.QueueUserWorkItem(saved.ProssecClient, connection);
}
}
}
}
class savedObject
{
Dictionary<string, StreamWriter> dic = new Dictionary<string, StreamWriter>();
StreamReader[] sr1 = new StreamReader[100];
StreamWriter[] sw1 = new StreamWriter[100];
string[] name = new string[100];
int m;
int a;
int g;
string word;
public string AllWords(string sit)
{
word += sit + " ";// here i concat them
return word;
}
public string word2()
{
return word;
}
public void ProssecClient(object o)
{
TcpClient connection = o as TcpClient;
if (connection == null)
{
return;
}
StreamReader sr = new StreamReader(connection.GetStream());
StreamWriter sw = new StreamWriter(connection.GetStream());
sr1[a++] = new StreamReader(connection.GetStream());
sw1[m++] = new StreamWriter(connection.GetStream());
string word2 = "";
sw.WriteLine("Please, fill your name: ");
name[g++] = sr.ReadLine();
if (name[g] != null && sw1[m] != null)
{
dic.Add(name[g], sw1[m]);
}
try
{
while (true)
{
int i = 0;
word2 = AllWords(sr.ReadLine());
for (i = 0; i < 3; i++)
{
if (sw1[i] != null)
{
sw1[i].WriteLine( name[i] + ": " + word2);// here is the words that are sent..
sw1[i].Flush();
}
}
}
}
catch { Console.WriteLine("client left"); }
}
}
This is one of my first issues. Whenever I exit out the program, tcpClient.Connect() takes forever to close. I've tried a ton of things, and none of them seem to work.
Take a look at the CreateConnection() thread, if the client isn't connected yet... and I close the program, it takes forever to close. If it IS connected, it closes immediately. I know this can be done with some kind of timeout trick, but i've tried a few and none of them worked.
Please provide a code example if you can.
Also, is there any good tutorial out there for C# on reading/writing the actual bytes with a buffer instead of this version that just does masterServer.writeLine() and masterServer.readline() or are they both just as efficient?
If you see anything else to help me improve this... by all means, go ahead. I'm trying to teach myself how to do this and I have no help, so don't let me go on doing something wrong if you see it!!! Thanks guys!
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
namespace RemoteClient
{
public partial class Form1 : Form
{
private int MyPort = 56789;
private IPAddress myIp = IPAddress.Parse("210.232.115.79");
private IPAddress serverIp = IPAddress.Parse("72.216.18.77"); // Master Server's IP Address
public static TcpClient masterServer = new TcpClient();
private StreamWriter responseWriter;
private StreamReader commandReader;
private Thread connectionThread;
private Thread commandsThread;
private bool RequestExitConnectionThread { get; set; }
private delegate void AddMessageDelegate(string message, int category);
private delegate void ConnectedDelegate();
private bool isConnected { get; set; }
public Form1()
{
InitializeComponent();
isConnected = false;
}
private void LogMessage(string message, int category)
{
if (category == 1)
{
ListViewItem item = new ListViewItem(message);
item.BackColor = Color.LightGreen;
item.UseItemStyleForSubItems = true;
Log.Items.Add(item).SubItems.Add(DateTime.Now.ToString());
}
if (category == 2)
{
ListViewItem item = new ListViewItem(message);
item.BackColor = Color.Orange;
item.UseItemStyleForSubItems = true;
Log.Items.Add(item).SubItems.Add(DateTime.Now.ToString());
}
if (category == 3)
{
ListViewItem item = new ListViewItem(message);
item.BackColor = Color.Yellow;
item.UseItemStyleForSubItems = true;
Log.Items.Add(item).SubItems.Add(DateTime.Now.ToString());
}
if (category == 0)
{
Log.Items.Add(message).SubItems.Add(DateTime.Now.ToString());
}
}
private void Connected()
{
LogMessage("Found and Accepted Master Server's connection. Waiting for reply...",1);
Status.Text = "Connected!";
Status.ForeColor = Color.Green;
commandsThread = new Thread(new ThreadStart(RecieveCommands));
sendClientInfo();
}
private void exitButton_Click(object sender, EventArgs e)
{
Disconnect();
exitButton.Enabled = false;
exitButton.Text = "Closing...";
if (connectionThread != null)
{
while (connectionThread.IsAlive)
{
Application.DoEvents();
}
}
this.Close();
}
private void Form1_Load(object sender, EventArgs e)
{
Connect();
}
private void Disconnect()
{
RequestExitConnectionThread = true;
if (masterServer != null)
masterServer.Close();
if (connectionThread != null)
connectionThread.Abort();
LogMessage("Closing Client. Please wait while Program threads end.", 2);
}
private void Disconnected()
{
Status.Text = "Disconnected";
Status.ForeColor = Color.Red;
Connect();
}
private void Connect()
{
LogMessage("Attempting to connect to Master Server...", 1);
connectionThread = new Thread(new ThreadStart(CreateConnection));
connectionThread.Start();
}
private void CreateConnection()
{
int i = 1;
bool success = false;
while (!success)
{
try
{
using (masterServer = new TcpClient())
{
IAsyncResult result = masterServer.BeginConnect(serverIp, MyPort, null, null);
success = result.AsyncWaitHandle.WaitOne(1000, false);
}
if (success)
{
BeginInvoke(new ConnectedDelegate(this.Connected), new object[] {});
break;
}
else
{
Thread.Sleep(2000);
BeginInvoke(new AddMessageDelegate(LogMessage), new object[] { "Connection Retry # " + i.ToString() + ". Master Server hasn't been started yet.", 3 });
}
}
catch
{
MessageBox.Show("Error!");
}
i++;
}
}
private void RecieveCommands()
{
MessageBox.Show("Hello!");
commandReader = new StreamReader(masterServer.GetStream());
string CommandResponse = commandReader.ReadLine();
string Command = null;
if (CommandResponse != null)
MessageBox.Show("Recieved Command that was NOT null!");
if (CommandResponse != null)
{
MessageBox.Show("Recieved null response!");
BeginInvoke(new AddMessageDelegate(LogMessage), new object[] { "Disconnected From Master Server. Reason: Recieved Null response.", 1 });
Disconnected();
}
else if (CommandResponse.StartsWith("0"))
{
MessageBox.Show("Recieved 0 as a response!");
Command = CommandResponse.Substring(2).Trim();
isConnected = false;
BeginInvoke(new AddMessageDelegate(LogMessage), new object[] { "Disconnected From Master Server. Reason: " + Command, 1 });
}
else if (CommandResponse.StartsWith("1"))
{
MessageBox.Show("Recieved 1 as a response!");
isConnected = true;
BeginInvoke(new AddMessageDelegate(LogMessage), new object[] { "Connected to Master Server Successfully.", 1 });
}
}
//************************** RESPONSE'S BELOW HERE ************************* \\
private void sendClientInfo()
{
responseWriter = new StreamWriter(masterServer.GetStream());
responseWriter.WriteLine(myIp.ToString());
responseWriter.Flush();
}
}
}
Sorry, after testing it: NO, it does not use an async waithandle, it blocks the process :(
I prefer this solution, which also blocks the process but only by the period you specify, in this case 5 seconds:
using (TcpClient tcp = new TcpClient())
{
IAsyncResult ar = tcp.BeginConnect("127.0.0.1", 80, null, null);
System.Threading.WaitHandle wh = ar.AsyncWaitHandle;
try
{
if (!ar.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5), false))
{
tcp.Close();
throw new TimeoutException();
}
tcp.EndConnect(ar);
}
finally
{
wh.Close();
}
}
From: http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/2281199d-cd28-4b5c-95dc-5a888a6da30d
The following example uses both async connection and async timeout control:
var tcp = new TcpClient();
var ar = tcp.BeginConnect(Ip, Port, null, null);
Task.Factory.StartNew(() =>
{
var wh = ar.AsyncWaitHandle;
try
{
if (!ar.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5), false))
{
// The logic to control when the connection timed out
tcp.Close();
throw new TimeoutException();
}
else
{
// The logic to control when the connection succeed.
tcp.EndConnect(ar);
}
}
finally
{
wh.Close();
}
});
connect with timeout of 2000 ms:
AutoResetEvent connectDone = new AutoResetEvent( false );
TcpClient client = new TcpClient();
client.BeginConnect(
"127.0.0.1", 80,
new AsyncCallback(
delegate( IAsyncResult ar ) {
client.EndConnect( ar );
connectDone.Set();
}
), client
);
if( !connectDone.WaitOne( 2000 ) ) {
Console.WriteLine( "network connection failed!" );
Environment.Exit( 0 );
}
Stream stream = client.GetStream();
Adding a check within your connection process to cancel it if the program is exiting should help.
Try adding this in CreateConnection() inside your while(!success) loop but before your try block:
if(RequestExitConnectionThread)
{
break;
}
Here's an example of an asynchronous BeginConnect() call:
myTcpClient.BeginConnect("localhost", 80, OnConnect, null);
OnConnect function:
public static void OnConnect(IAsyncResult ar)
{
// do your work
}