You are seeing a code written to see time data from Rasberry pi in a text box named textBox1 in a c# windows form application on another computer. When run, the print statements work fine but the form does not load.
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.Sockets;
namespace WindowsFormsApp4
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Console.WriteLine("Trying to establish connection...");
TcpClient client = new TcpClient();
client.Connect("192.168.104.15", 4900);
Console.WriteLine("Connection established.");
NetworkStream stream = client.GetStream();
byte[] buffer = new byte[1];
int bytesReceived;
while (true)
{
bytesReceived = stream.Read(buffer, 0, buffer.Length);
if (bytesReceived == 0)
break;
Console.WriteLine("Data received.");
string receivedData = System.Text.Encoding.ASCII.GetString(buffer, 0, bytesReceived);
textBox1.Text += receivedData;
Array.Clear(buffer, 0, buffer.Length);
Console.WriteLine("Data printed.");
}
client.Close();
}
}
}
I did the same process from python to python, it was working fine. I haven't done anything specific to this problem for C#.
The
while(true)
is blocking the UI thread.
So the load form never finish.
Try putting the while(true) to a new thread.
so the Winform UI thread is not blocked.
Your code shows an attempt read a TCP connection and your comment clarifies that you "want to receive data in an infinite loop". One way to achieve this outcome without blocking the main form's load method is to do your IO using async methods:
public partial class MainForm : Form
{
public MainForm() => InitializeComponent();
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
_tcpTask = execTcpPingLoop();
}
private Task? _tcpTask = null;
private async Task execTcpPingLoop()
{
Console.WriteLine("Trying to establish connection...");
using (TcpClient client = new TcpClient())
{
try
{
await client.ConnectAsync(
"192.168.104.15",
4900,
new CancellationTokenSource(TimeSpan.FromSeconds(5)).Token
);
Console.WriteLine("Connection established.");
byte[] buffer = new byte[1];
int bytesReceived;
while (true)
{
using (NetworkStream stream = client.GetStream())
{
bytesReceived = await stream.ReadAsync(buffer, 0, buffer.Length);
}
if (!bytesReceived.Equals(0))
{
Console.WriteLine("Data received.");
string receivedData = System.Text.Encoding.ASCII.GetString(buffer, 0, bytesReceived);
textBox1.AppendText(receivedData);
Array.Clear(buffer, 0, buffer.Length);
Console.WriteLine("Data printed.");
}
}
}
catch (Exception ex)
{
Debug.Assert(false, ex.Message);
}
}
}
}
Test
Since I don't have access to your TCP connection, here's the code I used to test this answer:
public partial class MainForm : Form
{
public MainForm() => InitializeComponent();
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
_tcpTask = execTcpPingLoop();
}
private Task? _tcpTask = null;
private async Task execTcpPingLoop()
{
Console.WriteLine("Trying to establish connection...");
using (TcpClient client = new TcpClient())
{
try
{
richTextBox.Append("Trying to establish connection...", color: Color.Blue);
while (true)
{
var pingReply = new Ping().Send(
"www.google.com",
timeout: (int)TimeSpan.FromSeconds(10).TotalMilliseconds,
buffer: new byte[0],
options: new PingOptions(64, true));
richTextBox.Append($"{pingReply.Status}: Elapsed={pingReply.RoundtripTime}");
// Wait out the delay asynchronously
await Task.Delay(1000);
}
}
catch (Exception ex)
{
Debug.Assert(false, ex.Message);
}
}
}
}
Where Append is an extension for RichTextBox:
static class Extensions
{
public static void Append(this RichTextBox #this, string? text = null, bool newLine = true, Color? color = null)
{
if (newLine && !string.IsNullOrWhiteSpace(text))
{
text = $"{text}{Environment.NewLine}";
}
if (color != null)
{
var colorB4 = #this.ForeColor;
#this.SelectionColor = (Color)color;
#this.AppendText(text);
#this.SelectionColor = colorB4;
}
else #this.AppendText(text);
}
}
Related
I'm having a hard time naming this question and solving my problem.
I'm challenging myself in creating a chat server with multiple chat clients.
I've created a server that instantiates a new ClientManager object upon receiving a new connection via TCP. I'm missing various bits of management currently so ignore that as I'm focusing on figuring this bit out first:
Once the connection is established the ClientManager creates a new background worker for receiving streams. What I'm having trouble is once the stream is read, how can I forward that information back to my main server class to distribute amounts to the other clients (chat clients).
Once again, I'm missing a few management options such as threading, semaphores, etc but that will come as I build it out.
Here is how my server established a connection:
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.ComponentModel;
namespace ChatServer
{
class Program
{
private IPAddress localAddr;
private int serverPort;
private BackgroundWorker bwListener;
private List<ClientManager> clients;
private TcpListener server;
static void Main(string[] args)
{
Program progInstance = new Program();
progInstance.clients = new List<ClientManager>();
progInstance.server = null;
try
{
// Set the TcpListener on port 13000.
progInstance.serverPort = 13000;
progInstance.localAddr = IPAddress.Parse("127.0.0.1");
// Start to listen
progInstance.bwListener = new BackgroundWorker();
progInstance.bwListener.WorkerSupportsCancellation = true;
progInstance.bwListener.DoWork += new DoWorkEventHandler(progInstance.ServerListen);
progInstance.bwListener.RunWorkerAsync();
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
//progInstance.server.Stop();
}
Console.WriteLine("\nHit enter to continue...");
Console.Read();
}
private void ServerListen(object sender, DoWorkEventArgs e) {
this.server = new TcpListener(this.localAddr, this.serverPort);
this.server.Start();
// Enter the listening loop.
while (true)
{
Console.Write("Waiting for a connection... \n");
Socket client = server.AcceptSocket();
this.AcceptClientConnection(client);
}
}
private void AcceptClientConnection(Socket client) {
ClientManager newClient = new ClientManager(client);
this.clients.Add(newClient);
}
private void DisplayClientConnections() {
}
}
}
And this is the ClientManager
using System;
using System.Net.Sockets;
using System.ComponentModel;
namespace ChatServer
{
class ClientManager
{
NetworkStream stream;
private Socket socket;
private BackgroundWorker bwReceiver;
//data = null;
public ClientManager(Socket socket)
{
this.socket = socket;
this.stream = new NetworkStream(this.socket);
this.bwReceiver = new BackgroundWorker();
this.bwReceiver.DoWork += new DoWorkEventHandler(StartReceive);
this.bwReceiver.RunWorkerAsync();
}
private void StartReceive(object sender, DoWorkEventArgs e) {
String data = null;
Byte[] bytes = new Byte[256];
int i;
while (this.socket.Connected) {
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
}
}
}
}
}
I was thinking that the server should somehow retrieve this information and then write it to the stream, or would I just do that would I just write back to the stream from the ClientManager and then have my actual clients listen and receive? I'm just super lost how to handle this portion of the chat server.
In the following code, the messages from the server are received on one thread (inside while loop). And, the messages to the server are sent on main GUI thread (on sendButton_Click)
using System.Windows.Forms;
using System.Net.Sockets;
using System.Threading;
namespace SimulatedClient
{
public partial class ClientForm : Form
{
TcpClient clientSocket = new TcpClient();
NetworkStream serverStream = default(NetworkStream);
string readdata = null;
public ClientForm()
{
InitializeComponent();
}
private void connectButton_Click(object sender, EventArgs e)
{
clientSocket.Connect(hostTextbox.Text, Int32.Parse(portTextBox.Text));
Thread ctThread = new Thread(getMessages);
ctThread.Start();
}
public void getMessages()
{
string returnData;
while (true)
{
serverStream = clientSocket.GetStream();
var buffersize = clientSocket.ReceiveBufferSize;
byte[] instream = new byte[buffersize];
serverStream.Read(instream, 0, buffersize);
returnData = System.Text.Encoding.ASCII.GetString(instream);
readdata = returnData;
UpdateReceivedPressureLabelText(readdata);
//msg();
}
}
void UpdateReceivedPressureLabelText(string value)
{
Action action = () => incomingTextBox.Text = value;
this.Invoke(action);
}
//private void msg()
//{
// if (this.InvokeRequired)
// {
// this.Invoke(new MethodInvoker(msg));
// }
// else
// {
// incomingTextBox.Text = readdata;
// }
//}
private void sendButton_Click(object sender, EventArgs e)
{
byte[] outstream = Encoding.ASCII.GetBytes(outgoingTextBox.Text);
serverStream.Write(outstream, 0 , outstream.Length);
serverStream.Flush();
}
}
}
QUESTION: Is it ok to do so i.e. is it ok to receive messages using one thread and send messages on another thread for the same clientSocket? The program is working but I am not sure if it could lead to some problem?
I finally got the program to work as I wanted is reading the data from the telnet port for every scan it triggers, but now the only problem I am getting is that is reading the data if I display it in the console but I need it display into my main display which will be a text box multiline, can you see why I am getting this
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace BarcodeReceivingApp
{
public partial class BarcodeReceivingForm : Form
{
public BarcodeReceivingForm()
{
InitializeComponent();
}
private Thread _readWriteThread;
private TcpClient _client;
private NetworkStream _networkStream;
private void btn_ConnectToTelnetPort_Click(object sender, EventArgs e)
{
// connection tcp/ip
const string hostname = "myipaddress";
const int port = 23;
ServerSocket(hostname, port);
//Connect();
}
public void ServerSocket(string ip, int port)
{
try
{
_client = new TcpClient(ip, port);
lbl_ConnectionMessage.Text = #"Connected to server.";
}
catch (SocketException)
{
MessageBox.Show(#"Failed to connect to server");
return;
}
//Assign networkstream
_networkStream = _client.GetStream();
//start socket read/write thread
_readWriteThread = new Thread(ReadWrite);
_readWriteThread.Start();
}
private void ReadWrite()
{
var received = "";
//Read first thing givent o us
received = Read();
//Console.WriteLine(received);
txt_BarcodeDisplay.Text = received + Environment.NewLine;
//txt_BarcodeDisplay.Text = recieved.ToString();
//Set up connection loop
while (true)
{
var command = btn_StopConnection.Text;
if (command == "STOP1")
break;
//write(command);
received = Read();
//Console.WriteLine(received);
txt_BarcodeDisplay.Text += received + Environment.NewLine;
}
// possible method to end the port connection
}
public string Read()
{
byte[] data = new byte[1024];
var received = "";
var size = _networkStream.Read(data, 0, data.Length);
received = Encoding.ASCII.GetString(data, 0, size);
return received;
}
private void btn_StopConnection_Click(object sender, EventArgs e)
{
_networkStream.Close();
_client.Close();
}
}
}
Here is I am adding the error and is coming from the ReadWrite method
enter image description here
So you'll have to have a loop somewhere to have your program keep checking the Stream. Usually the easiest was is with a Boolean indicator, so something list this:
Boolean openConnection = false;
This would need to be class level. Then inside your connect method, you loop and listen. Something like this.
NetworkStream ns = server.GetStream();
openConnection = True;
Task.Factory.StartNew(() =>
{
while (openConnection)
{
ns.Read(data, 0, data.Length);
var stringData = Encoding.ASCII.GetString(data, 0, 1024);
dataToAdd.Add(stringData);
foreach (var list in dataToAdd)
{
txt_BarcodeDisplay.Text += list + Environment.NewLine;
}
Thread.Sleep(2000);
}
}
);
So this is a lot to unpack, but basically you're saying, go read what comes in from the network, do it until the openConnection variable is set to false. Oh and since we don't want to peg the processor at 100%, Sleep the thread so we only check every 2 seconds.
This is a rough start, but I hope it will give you an idea of the direction you need to take this.
I am currently learning to program a chat room application that uses a server. So far everything works fine if I run the server and multiple instances of the application on a single machine. When I try to run the server on one machine and the actual chat application from another, I get an exception that reads "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 (Ipaddress)(port)"
Server side code:
using System;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Collections;
using System.Text;
using System.Threading;
namespace ChatAppServer
{
class Program
{
public static Hashtable ClientList = new Hashtable();
const int PORT = 321;
string localIp;
static void Main(string[] args)
{
TcpListener sckServer = new TcpListener(PORT);
TcpClient sckClient = default(TcpClient);
int counter = 0;
sckServer.Start();
Console.WriteLine("Chat Server is now Running ....");
counter = 0;
//Parser myParser = new Parser();
while (true)
{
counter = counter + 1;
sckClient = sckServer.AcceptTcpClient();
string clientData = "";
byte[] recieveData = new byte[10025];
NetworkStream netStream = sckClient.GetStream();
netStream.Read(recieveData, 0, (int)sckClient.ReceiveBufferSize);
clientData = System.Text.Encoding.ASCII.GetString(recieveData);
clientData = clientData.Substring(0, clientData.IndexOf("$"));
ClientList.Add(clientData, sckClient);
Broadcast(clientData + " joined the chat", clientData, false);
Console.WriteLine(clientData + " connected to the chat");
handleClient client = new handleClient();
client.ClientStart(sckClient, clientData, ClientList);
}
sckClient.Close();
sckServer.Stop();
Console.WriteLine("exit");
Console.ReadLine();
}
public static void Broadcast(string msg, string userName, bool flag)
{
foreach (DictionaryEntry Item in ClientList)
{
TcpClient sckBroadcast;
sckBroadcast = (TcpClient)Item.Value;
NetworkStream broadcastStream = sckBroadcast.GetStream();
Byte[] broadcastData = null;
if (flag == true)
{
broadcastData = Encoding.ASCII.GetBytes(userName + ": " + msg);
}
else
{
broadcastData = Encoding.ASCII.GetBytes(msg);
}
broadcastStream.Write(broadcastData, 0, broadcastData.Length);
broadcastStream.Flush();
}
}
public class handleClient
{
TcpClient sckClient;
string clId;
Hashtable ClientList;
public void ClientStart(TcpClient inSckClient, string clientId, Hashtable clist) {
this.sckClient = inSckClient;
this.clId = clientId;
this.ClientList = clist;
Thread ctThread = new Thread(runChat);
ctThread.Start();
}
private void runChat() {
int requestCount = 0;
byte[] recieveData = new byte[10025];
string clientData = "";
string rCount = null;
while ((true))
{
try
{
requestCount += 1;
NetworkStream netStream = sckClient.GetStream();
netStream.Read(recieveData, 0, (int)sckClient.ReceiveBufferSize);
clientData = System.Text.Encoding.ASCII.GetString(recieveData);
clientData = clientData.Substring(0, clientData.IndexOf("$"));
Console.WriteLine(clId + " : " + clientData);
rCount = Convert.ToString(requestCount);
Program.Broadcast(clientData, clId, true);
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
}
}
}
Chat room application code:
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;
//Need for the application
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace ChatApp
{
public partial class Form1 : Form
{
System.Net.Sockets.TcpClient sckClient = new System.Net.Sockets.TcpClient();
NetworkStream svrStream = default(NetworkStream);
string recieveData = null;
public Form1()
{
InitializeComponent();
btnSend.Enabled = false;
}
private void btnConnect_Click(object sender, EventArgs e)
{
recieveData = "Connected to Server";
msg();
int serverPort = Convert.ToInt32(txtServerPort.Text);
sckClient.Connect(txtServerIp.Text, serverPort);
svrStream = sckClient.GetStream();
byte[] outStream = System.Text.Encoding.ASCII.GetBytes(txtUserName.Text + "$");
svrStream.Write(outStream, 0, outStream.Length);
svrStream.Flush();
Thread ctThread = new Thread(MessageCallBack);
btnSend.Enabled = true;
btnConnect.Enabled = false;
txtUserName.Enabled = false;
txtServerIp.Enabled = false;
txtServerPort.Enabled = false;
ctThread.Start();
}
private void MessageCallBack()
{
while(true)
{
svrStream = sckClient.GetStream();
int buffSize = 0;
byte[] inStream = new byte[10025];
buffSize = sckClient.ReceiveBufferSize;
svrStream.Read(inStream, 0, buffSize);
string returnData = System.Text.Encoding.ASCII.GetString(inStream);
recieveData = "" + returnData;
msg();
}
}
//function to display data strings
private void msg()
{
if (this.InvokeRequired)
{
this.Invoke(new MethodInvoker(msg));
}
else
{
lstMessage.Items.Add(recieveData);
}
}
private void btnSend_Click(object sender, EventArgs e)
{
byte[] outStream = System.Text.Encoding.ASCII.GetBytes(txtMessage.Text + "$");
svrStream.Write(outStream, 0, outStream.Length);
svrStream.Flush();
txtMessage.Text = "";
}
I have two troubles with your code :
Do not use .ReceiveBufferSize value because it's a different value of your byte array length. And you can have an index out of range exception.
You have a problem of concurrency in the server side. More than 1 thread try to access to the ClientList and this collection is not thread-safe.
To resolve this, you can use the lock keyword
private static object _lock = new object();
//...
lock (_lock)
{
ClientList.Add(clientData, sckClient);
}
lock (_lock)
{
Broadcast(clientData + " joined the chat", clientData, false);
}
//...
lock (_lock)
{
Program.Broadcast(clientData, clId, true);
}
As you're a beginner, i would give you some tips.
Try to use the asynchronous network functions (better than raw threads), an example there.
There is a lot of tutorials about safety with severals connections in C# (with some thing else, better, than the lock keyword).
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
tcp/ip client server not working over internet
i spent the last week working on a simple windows form application that' s supposed to send a couple of integer numbers from client to server or from server to client. So far i have only managed to make it work for lanns, any idea about how to make it work on the open internet ?
Here' s the code in case you need it (also call me noob but i can' t get how this site handles code, ... does not do what i thought it did so feel free to edit my post in case i fail2format)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace client_server_penta
{
public class Client
{
#region Fields
private int turno = 1;
private TcpClient[] clients = new TcpClient[1]; //used to remember the active client
private int CoordinateX, CoordinateY; //coordinates, they are used by the application
#endregion
public Client(string address)
{
TcpClient client = new TcpClient();
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse(address), 3000);
client.Connect(serverEndPoint);
clients[0] = client;
Thread ReadFromServer = new Thread(new ParameterizedThreadStart(this.ReadHandler));
ReadFromServer.Start(client);
}
public void SendData(int a, int b)
{
NetworkStream clientStream = clients[0].GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes(a.ToString() + '$' + b.ToString() + '$');
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
}
public int ReadCoordinateX()
{
return this.CoordinateX;
}
public int ReadCoordinateY()
{
return this.CoordinateY;
}
private void ReadHandler(object client)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
byte[] buffer;
int bytesRead;
while (true)
{
buffer = new byte[10];
bytesRead = 0;
try
{
bytesRead = clientStream.Read(buffer, 0, buffer.Length);
}
catch
{
//an uknown error has occurred
break;
}
if (bytesRead == 0)
{
//the client has disconnected from the server
break;
}
//data received
ASCIIEncoding encoder = new ASCIIEncoding();
OnDataReceived(encoder.GetString(buffer, 0, buffer.Length));
}
tcpClient.Close();
}
private void OnDataReceived(string text)
{
string first_number = "";
string second_number = "";
int index = 0;
while (text[index] != '$')
first_number += text[index++];
index++;
while (text[index] != '$')
second_number += text[index++];
this.CoordinateX = Convert.ToInt32(first_number);
this.CoordinateY = Convert.ToInt32(second_number);
var myForm = Application.OpenForms["Form2"] as Form2;
myForm.Text = "Turno N." + Convert.ToString(this.turno++);
}
}
}
//and here' s the server
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace client_server_penta
{
public class Server
{
private Thread listenThread;
private int turno = 1;
private TcpListener tcpListener;
private TcpClient[] clients = new TcpClient[1]; //used to remember the active client
private int CoordinateX, CoordinateY; //coordinates, they are used by the application
public Server(int port)
{
this.tcpListener = new TcpListener(IPAddress.Any, 3000);
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
public void SendData(int a, int b)
{
NetworkStream clientStream = clients[0].GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes(a.ToString()+'$'+b.ToString()+'$');
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
}
public int ReadCoordinateX()
{
return this.CoordinateX;
}
public int ReadCoordinateY()
{
return this.CoordinateY;
}
private void ListenForClients()
{
this.tcpListener.Start();
TcpClient client = this.tcpListener.AcceptTcpClient();
clients[0] = client;
Thread ReadFromClient = new Thread(new ParameterizedThreadStart(this.ReadHandler));
ReadFromClient.Start(client);
}
private void ReadHandler(object client)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
byte[] buffer = new byte[10];
int bytesRead;
while (true)
{
buffer = new byte[10];
bytesRead = 0;
try
{
bytesRead = clientStream.Read(buffer, 0, buffer.Length);
}
catch
{
break;
}
if (bytesRead == 0)
{
//the client has disconnected from the server
break;
}
//data received
ASCIIEncoding encoder = new ASCIIEncoding();
OnDataReceived(encoder.GetString(buffer, 0, buffer.Length));
}
tcpClient.Close();
}
private void OnDataReceived(string text)
{
string first_number = "";
string second_number = "";
int index = 0;
while (text[index] != '$')
first_number += text[index++];
index++;
while (text[index] != '$')
second_number += text[index++];
this.CoordinateX = Convert.ToInt32(first_number);
this.CoordinateY = Convert.ToInt32(second_number);
var myForm = Application.OpenForms["Form2"] as Form2;
myForm.Text = "Turno N."+Convert.ToString(this.turno++);
}
}
}
Have you opened the 3000 port on your firewall on the two sides ?
Yes of course ^^
If you have routers, don't forget to edit the configurations too.