Sending network data on button click - conflicts between threads in c# - c#

so i've got a Visual Studio C# WindowsForms program. It has the ability to open up a socket in the background to let tcp clients join. they can then exchange data.
the problem is that writing data to that tcp socket is a problem for me. reading data is successfull.
so my form1:
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private TcpListener listener;
private Socket socket;
...
private void Form1_Load(object sender, EventArgs e)
{
comboBox1.SelectedIndex = 0;
webBrowser1.GoHome();
const int LIMIT = 1; //5 concurrent clients
listener = new TcpListener(IPAddress.Any, 8080);
listener.Start();
for (int i = 0; i < LIMIT; i++)
{
Thread t = new Thread(() => {
socket = EmployeeTCPServer.accepting(listener, this);
});
t.Start();
}
toolStripStatusLabel1.Text = "Waiting for Connection";
listBox1.Items.Add("Waiting");
}
...
private void button3_Click(object sender, EventArgs e)
{
StreamWriter sw = new StreamWriter(new NetworkStream(socket));
sw.WriteLine("-> Stuff");
}
The accepting of the client must be threaded in case the form continues working, which should be the source of all evil. And my TCP Server Class:
class EmployeeTCPServer
{
public static Socket accepting(TcpListener plistener, Form1 parent)
{
Socket soc = plistener.AcceptSocket();
parent.SetText("Connection accepted");
Stream s = new NetworkStream(soc);
StreamReader sr = new StreamReader(s);
StreamWriter swa = new StreamWriter(s);
swa.AutoFlush = true; // enable automatic flushing
swa.WriteLine("-> Connected to Iface");
Service(plistener, parent, soc);
return soc;
}
public static void Service(TcpListener plistener, Form1 parent, Socket psoc)
{
bool EMPFANG = true;
Stream s = new NetworkStream(psoc);
StreamReader sr = new StreamReader(s);
StreamWriter swa = new StreamWriter(s);
swa.AutoFlush = true;
while (EMPFANG)
{
string name = sr.ReadLine();
parent.LBSetText(name);
if(name=="exit")
{
swa.WriteLine("-> Exit OK");
EMPFANG = false;
}
}
psoc.Close();
}
}
The problem crashes when i click on "Antworten" (Button3). It says that sw is NULL, which for me means that the returning of the socket descriptor doesn't work.
I also tried to make a new method in the tcp server class (something like "send_msg_to_client(string pmessage)") but then i dont know how to call that method.
So which method is the right one and how can i send data on button click?
Thanks in advance for help!

It sounds like you want a simple "chat" system with specific messages send between the client and the host.
Try to have a look at this project:
http://www.eng.northampton.ac.uk/~espen/CSY2026/CSY2026CSharp5.htm
Maybe it can be to some inspiration.
Let me know if it helps!

Related

C# Winform : Error while trying to launch TCP client application

I have a C# Winform application trying to launch a node server.
However the code for this is written in a different cs file, Class1.cs rather than in Form.cs itself. I need to keep this separated in different files. Below is my Class1.cs file:
using System.Net.Sockets;
namespace NodeApp
{
class Class1
{
static string HOST = "localhost";
static int PORT = 9999;
static TcpClient client;
NetworkStream nwStream = client.GetStream();
public void NodeServer()
{
string strCmdText;
strCmdText = "/C node C:\\Desktop\\Test.js";
Process process = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = "cmd.exe";
startInfo.Arguments = strCmdText;
process.StartInfo = startInfo;
process.Start();
}
}
}
Now when I call the function from my Form.cs file, like below:
using System.Net.Sockets;
namespace NodeApp
{
public partial class Form1 : Form
{
Class1 cl = new Class1();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
cl.NodeServer();
}
am getting System.NullReferenceException at NetworkStream nwStream = client.GetStream();.
as no client is connected. But in-order to achieve that, the Node server should be running first correct ?
I was able to achieve this in a console based application where I called the NodeServer() method before the client.Connect() method in the Main function
static void Main(string[] args)
{
NodeSever();
Thread.Sleep(1500);
Console.WriteLine("Connecting to Node Server....");
bool connected = false;
client = new TcpClient();
while(!connected)
{
Thread.Sleep(2000);
try
{
client.Connect(HOST, PORT);
connected = true;
}
catch (SocketException e)
{
}
}
}
How can I replicate the same in a Winform application on Form_load method (where methods are defined in Class1.cs itself). Is Form_Load the right event to call the NodeServer() method?
You should not mix direct member initialisation and constructor logic. This makes it hard to understand the code flow.
This line declares a variable and initializes it:
NetworkStream nwStream = client.GetStream();
It is equivalent to changing the above line to:
NetworkStream nwStream;
and adding the following as the first line of the constructor:
nwStream = client.GetStream();
This makes it obvious that the client is not initialized.
In your case, just move the connection code to a separate method:
public void Connect()
{
client = new TcpClient();
while(!connected)
{
Thread.Sleep(2000);
try
{
client.Connect(HOST, PORT);
connected = true;
}
catch (SocketException e)
{
}
}
}
I also suggest to remove the static from the declaration of client.

C# TCPListener keep listening after application shutdown only for the first time

I have an issue with my application,
I have a TCPListener which listen let's say on port 14000
After the application is being closed I can see on the CMD that the listener is still listening.
At the second run of the application as expected I cant start the listener on the same port (14000) because it is already taken, I am changing the application port to 15000 on the second running, work wonderful and the listener is being CLOSED after the application is being shut down,
I assume that on the first run, the first listener on port 14000 stays open after the app is dead, on the second run the application closed/open the listener on port 15000 very well, why is this happen? I thought maybe it is about the port 14000 I've switched the orders of the opening ports (first opened 15000) and saw that the 15000 stays open and the 14000 (on the second run) closed and open correctly, Why at the first run the listener not being closed??
The code to my server:
class Server : IDisposable
{
private const int TIMER_PERIOD = 60 * 1000; // ms
private string servePort;
private string serverIP;
byte[] DataReceived = new byte[1024];
Action<string> MssageReceiveCallback;
private bool isListening = false;
static Timer serverTimer = null;
private TcpListener _Server;
private Dictionary<int, TcpClient> clientsList = new Dictionary<int, TcpClient>();
private bool serverListening = true;
private static int ClientInstance = 0;
public Server(string _serverIP, string _serverPORT, Action<string> messageReceiveCallback)
{
serverIP = _serverIP;
servePort = _serverPORT;
MssageReceiveCallback = messageReceiveCallback;
// InitilizeServer();
}
private void InitilizeServer()
{
_Server = new TcpListener(IPAddress.Parse(serverIP), int.Parse(servePort));
// if (serverTimer == null)
// serverTimer = new Timer(new TimerCallback(OnTimerCallback), null, TIMER_PERIOD, TIMER_PERIOD);
Task.Run(() =>
{
try
{
_Server.Start();
while (_Server != null)
{
TcpClient tcpClient;
try
{
tcpClient = _Server.AcceptTcpClient();
}
catch
{
continue;
}
Task.Run(() =>
{
ClientInstance++;
int currentinstance = ClientInstance;
clientsList.Add(currentinstance, tcpClient);
try
{
while (tcpClient.Connected && serverListening)
{
if (tcpClient.GetStream().DataAvailable)
{
int actualBufferlength = tcpClient.GetStream().Read(DataReceived, 0, DataReceived.Length);
byte[] data = new byte[actualBufferlength];
Buffer.BlockCopy(DataReceived, 0, data, 0, actualBufferlength);
string asciiMessage = Encoding.ASCII.GetString(data);
MssageReceiveCallback(asciiMessage);
}
else
{
Thread.Sleep(5);
}
}
}
catch (Exception ex)
{
}
finally
{
clientsList[currentinstance].Close();
clientsList.Remove(currentinstance);
}
});
}
}
catch (Exception ex)
{
}
});
}
public void StartServer()
{
InitilizeServer();
isListening = true;
}
public void SendMessage(string msg)
{
byte[] data = ASCIIEncoding.ASCII.GetBytes(msg);
foreach (TcpClient client in clientsList.Values)
{
client.GetStream().Write(data, 0, data.Length);
}
}
public void Dispose()
{
serverListening = false;
foreach (var item in clientsList.Values)
{
if (item.Connected)
item.Close();
}
_Server.Server.Close();
}
}
UPDATE:
I've check in TCPView to see which application the listener bind to and found this:
It looks like the listener available for un exist process
The biggest problem here, I think (I've pointed out other problems in the comments) is that TCP shutdown requires network communications and by default prevents socket reuse for a period of time.
The function you need to get to is Socket.SetSocketOption, specifically the ReuseAddress option. You should be able to get at it via the Server property on the TcpListener. Pay attention that it needs to be done before you actually start the listener listening.
You could try putting:
_Server.Server =null;
After close.

TCPIP connection in c# and data sending/receiving in another threads

I have a problem with my TCPIP connection Form programm.
I have a code, where I'm trying to send and receive some data from server.
The main problem of my app is how to reconcile some threads:
myListenThread - to listening data from server
myReadStreamThread - to read data from server
System.Threading.Thread - main thread eg. to write data to server
captureThread - to do another things like capturing images from camera
Part of my code:
private void buttonConnect_Click(object sender, EventArgs e)
{
try
{
Connect();
Connected = true;
this.myListenThread = new Thread(new ThreadStart(Listen));
this.myListenThread.Start();
}
catch
{
MessageBox.Show("Invalid host! Try again.");
}
}
private void Listen()
{
this.myReadStreamThread = new Thread(new ThreadStart(ReadStream));
this.myReadStreamThread.Start();
while (Connected)
{
if (!myReadClient.Connected)
{
Connect();
}
}
}
private void Connect()
{
IPAddress IP = IPAddress.Parse(textboxIP.Text);
int PORT = Convert.ToInt32(textboxPORT.Text);
this.myReadClient = new TcpClient();
this.myReadClient.Connect(IP, PORT);//SOMETIMES HERE'S AN ERROR
this.myStream = this.myReadClient.GetStream();
Properties.Settings.Default.IP = Convert.ToString(IP);
Properties.Settings.Default.PORT = Convert.ToString(PORT);
Properties.Settings.Default.Save();
}
private void ReadStream()
{
while (true)
{
try
{
this.myReadBuffer = new byte[this.myReadClient.ReceiveBufferSize];
this.myBufferSize = myStream.Read(myReadBuffer, 0, this.myReadClient.ReceiveBufferSize);
if (myBufferSize != 0)
{
this.myString = Encoding.ASCII.GetString(myReadBuffer);
//myDelegate myDel;
//myDel = new myDelegate(Print);
//richtextboxRead.Invoke(myDel);
}
}
catch
{
break;
}
}
}
All is working correct when I'm connecting to server, but when I want to send some string the problem appears because of threads.
I decided to send string, by clicking Button3 and waiting until I receive string "1" from server using while loop:
private void button3_Click(object sender, EventArgs e)
{
this.captureThread = new Thread(new ThreadStart(() => this.newGame()));
this.captureThread.Start();
}
private bool newGame()
{
string command = "12345abc";
if (Connected)
{
WriteStream(command);
}
while (myBufferSize == 0 && myString !="1") { }
Thread.Sleep(2000);
...//doing other things
}
private void WriteStream(string command)
{
Connect();
this.myWriteBuffer = Encoding.ASCII.GetBytes(command);
this.myStream.Write(this.myWriteBuffer, 0, command.Length);
}
And the problem with connection and data send/receive problem appears, when it should write my string "command" - it doesn't react. MyBufferSize is always 0 and myString is always null. Sometimes an Error about connection appears when I click Button3 (assigned in code). I think it is because in captureThread I can't see any data from another threads. How to solve it?

UDP Connection Between Client and Server

Here is the server code of my program this is working, but after it sends data it gets stuck. I need it to be refreshed and ready for sending data again.
Server code:
private void button1_Click(object sender, EventArgs e) {
try {
String text = textBox1.Text;
UdpClient udpc = new UdpClient(text,8899);
IPEndPoint ep = null;
while (true) {
MessageBox.Show("Name: ");
string name = textBox2.Text;
if (name == "") break;
byte[] sdata = Encoding.ASCII.GetBytes(name);
udpc.Send(sdata, sdata.Length);
if (udpc.Receive(ref ep)==null) {
MessageBox.Show("Host not found");
} else {
byte[] rdata = udpc.Receive(ref ep);
string job = Encoding.ASCII.GetString(rdata);
MessageBox.Show(job);
}
}
} catch {
MessageBox.Show("Error Restarting");
}
Client code:
private void button1_Click(object sender, EventArgs e) {
try {
UdpClient subscriber = new UdpClient(8899);
IPAddress addr = IPAddress.Parse("127.0.0.2");
subscriber.JoinMulticastGroup(addr);
IPEndPoint ep = null;
for (int i = 0; i < 1; i++) {
byte[] pdata = subscriber.Receive(ref ep);
string strdata = Encoding.ASCII.GetString(pdata);
MessageBox.Show(strdata);
textBox1.Text = strdata;
pass = strdata;
}
subscriber.DropMulticastGroup(addr);
} catch {
Refresh();
MessageBox.Show("Not Found");
}
}
The Server can send data to one client . I want to send one client at a time. But after sending the data, the server gets stuck.
I need it do refresh and send data again for a client.
If I understood your code, from the server your sending data, then waiting for an answer. In the client, your just getting the data, but not sending anything back. And unless you provide timeout to the socket, it will wait indefinitely until something arrives.
You shouldn't use udpc.Receive() in the main UI thread (inside button1_Click). If you do, your aplication will hang until something arrives. Using a timeout isn't a solution either. The application will just hang until the timeout expires. Instead You must use a multiple threads. You can do so by using BeginReceive instead of Receive or by explicitly creating a new thread and using Receive there. If you google for "asynchronous udp sockets in c#" or something like that, then you will find plenty of examples on how to set it up correctly.
The udpc.Receive() Method on your server side, will Block Until a datagram receive from client.
UDP in not reliable. it means that server doesnt expect any ACK from other side. so you can simply remove this part of code. or if you need to ensure message arrival, run a separate thread for each client as follow:
private void button1_Click(object sender, EventArgs e) {
System.Threading.Thread Server_thread = new Thread(My_Send_Function);
Server_thread .Start();
}
private void My_Send_Function() {
try {
String text = textBox1.Text;
UdpClient udpc = new UdpClient(text,8899);
IPEndPoint ep = null;
while (true) {
MessageBox.Show("Name: ");
string name = textBox2.Text;
if (name == "") break;
byte[] sdata = Encoding.ASCII.GetBytes(name);
udpc.Send(sdata, sdata.Length);
if (udpc.Receive(ref ep)==null) {
MessageBox.Show("Host not found");
} else {
byte[] rdata = udpc.Receive(ref ep);
string job = Encoding.ASCII.GetString(rdata);
MessageBox.Show(job);
}
}
} catch {
MessageBox.Show("Error Restarting");
}
}

How do I get all servers' IP which are listening on specific port LAN?

How do I get all servers IP which are listening on specific port (Ex:9090) in LAN
I have already read some basics information about multicast,anycast ,unicast and broadcast and it seems like broadcast is the one meant for my application.
I am thinking of two ideas .. Use TCP protocol to Connect to all IP Addresses (192.168.1.1-254) in parallel on port 9090 and set a little time period to the connection timeout. just to check if there's any responce. (but it doesn't seem like a good idea)Use UDP protocol and broadcast a message like "hello" and check for response then get all IP Addresses which respond.
So which idea should I pick, are there better ideas to do it?
I would also like to know if my broadcast-ed message is received to the server and how to get the IP address of it.
I've done it with TCP to search all server that is listening on a specific port.
Its not an idle solution, but it worked for me.
I've created a userControl with a public function Initialize to pass the port that i want to scan for servers.
public ServerDiscovery()
{
InitializeComponent();
// statusLabel.Image = imageState.Images[2];
timer.Elapsed += timer_tick;
}
int port = 0;
bool busy = false; // to tell that the function is busy with scanning.
public void Initialize(int port)
{
this.port = port;
}
System.Timers.Timer timer = new System.Timers.Timer(5000);
List<SocketAsyncEventArgs> list = new List<SocketAsyncEventArgs>();
// this list to hold all sockets that created to connect to IP .. to DISPOSE it later
HashSet<string> usedIP = new HashSet<string>();
//usedIP will be explained later.
public IPEndPoint getAddress()
{ //this function to get the IPEndPoint of the selected server from listview.
if (listServer.SelectedItems.Count > 0)
{
if (listServer.SelectedItems[0].ImageIndex == 0)
{
ListViewItem item = listServer.SelectedItems[0];
IPEndPoint ep = new IPEndPoint(IPAddress.Parse(item.SubItems[1].Text), port);
return ep;
}
}
return null;
}
public void Refresh() //to scan for servers
{
if (!busy)
{
usedIP.Clear();
listServer.Items.Clear();
// statusLabel.Text = "Scanning for servers.";
// statusLabel.Image = Image.FromFile("loading.gif");
// btnRefresh.Enabled = false;
busy = true;
timer.Start();
IPAddress[] IpA = Dns.GetHostByName(Dns.GetHostName()).AddressList;
for (int j = 0; j < IpA.Length ; j++)
{
if (IpA[j].AddressFamily == AddressFamily.InterNetwork) // to make sure it's an IPV4
{
string scanIP = IpA[j].ToString().Substring(0, IpA[j].ToString().LastIndexOf(".")) + ".";
if (!usedIP.Contains(scanIP))
//usedIP is a hashset that holds the first 3 parts on an ip (ex:"192.168.1." from "192.168.1.30") i used this to avoid scanning the same ip addresses more than once .. like if i had a wireless network ip ("192.168.1.5") and an Ethernet Network ip ("192.168.1.5"). so with that hashset it will scan once.
{
usedIP.Add(scanIP);
Parallel.For(1, 255, i =>
{
Scan(scanIP + i);
});
}
}
}
}
}
private void Scan(string ipAdd)
{
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
SocketAsyncEventArgs e = new SocketAsyncEventArgs();
e.RemoteEndPoint = new IPEndPoint(IPAddress.Parse(ipAdd), port);
e.UserToken = s;
e.Completed += new EventHandler<SocketAsyncEventArgs>(e_Completed);
list.Add(e); // add the created socket to a list to dispose when time is up.
s.ConnectAsync(e);
}
private void e_Completed(object sender, SocketAsyncEventArgs e)
{
if (e.ConnectSocket != null) //if there's a responce from the server [e.ConnectSocket] will not be equal null.
{
StreamReader sr = new StreamReader(new NetworkStream(e.ConnectSocket));
ListViewItem item = new ListViewItem();
string[] cmd = sr.ReadLine().Split('<'); in my server constructor this line will receive a string like "PC_NAME<Available" ..
item.Text = cmd[0];
item.SubItems.Add(((IPEndPoint)e.RemoteEndPoint).Address.ToString());
item.SubItems.Add(cmd[1]);
if (cmd[1] == "Busy")
item.ImageIndex = 1;
else
item.ImageIndex = 0;
AddServer(item);
list.Remove(e); //active server should be remove from the list that holds the sockets and disposed.. because there's no need to keep connection after showing that this server is active.
((Socket)e.UserToken).Dispose();
}
}
delegate void AddItem(ListViewItem item);
private void AddServer(ListViewItem item)
{
if (InvokeRequired)
{
Invoke(new AddItem(AddServer), item); //just to add an item from a background thread.
return;
}
listServer.Items.Add(item);
}
private void timer_tick(object sender, EventArgs e)
{
busy = false; //when time's up .. set busy to false so we can scan again
timer.Stop();
foreach (var s in list) //dispose all sockets that's trying to connect and waiting for a response
{
try
{
((Socket)s.UserToken).Dispose();
}
catch { }
}
//this.Invoke((MethodInvoker)delegate // for design
// {
// btnRefresh.Enabled = true;
// btnRefresh.BorderStyle = Border3DStyle.Raised;
// statusLabel.Text = "Ready.";
// statusLabel.Image = imageState.Images[2];
// });
}
private void btnRefresh_Click(object sender, EventArgs e)
{
// btnRefresh.BorderStyle = Border3DStyle.Sunken;
Refresh();
}
// private void listServer_KeyUp(object sender, KeyEventArgs e)
// {
// if (e.KeyCode == Keys.F5)
// {
// btnRefresh_Click(sender, (EventArgs)e);
// }
// }
}
Again this's not an ideal solution that works on any case but it worked fine with me.

Categories