A method was created to be initialized with my Windows Form Application when I start it. However, when I call my method just below the InitializeComponent();, my whole Windows Form Application doesn't start, and it doesn't throw me any error.
Myclass mc = new Myclass();
public Interceptor()
{
InitializeComponent();
mc.myMethod();
>rest of the code
}
This is the class with the method:
public class Listener
{
public void myMethod() {
//Recieving the parameters to listen
Int32 port = 5000;
IPAddress ip = IPAddress.Parse("1.1.1.1");
TcpListener server = new TcpListener(ip, port);
//starting the server
server.Start();
//Accepting connection from the Client
Socket socket = server.AcceptSocket();
//Storing the data
byte[] bytes = new byte[4096];
int k = socket.Receive(bytes);
//???
ASCIIEncoding asen = new ASCIIEncoding();
string data = null;
data = Encoding.ASCII.GetString(bytes, 0, k);
//Reading all the data using the TextReader()
TextReader reader = new StringReader(data);
XmlSerializer serializer = new XmlSerializer(typeof(MyObject));
MyObject obj = (MyObject)serializer.Deserialize(reader);
string json = JsonConvert.SerializeObject(icx, Formatting.Indented, new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
});
string path = #"c:/temp";
string name = "test";
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
string fileName = $"{path}\\{name}.json";
File.WriteAllText(fileName, json);
}
}
As you guys can see, my method is deserializing a XML object and serializing to JSON object. When I add this method to a button, it works perfectly. I basically need this method to be initialized with my application, and the user doesn't need to press any button to run it. I spent thre days without any progress.
Hope I made myself clear.
Cheers!
Your Interceptor() method is the constructor of (what appears to be) the Form. So this is called when you create the form and the job of the constructor is initialisation of the form, settings defaults etc.
By placing your mc.myMethod() within the constructor you are actually forcing it to start your business logic already. This means, it will be performed before the form is finished being created (and shown).
So this is not good and as your code in this method blocks the UI thread then this is why you have this problem, because you don't allow the form to finished being created before you are processing data and blocking the UI.
You should instead use Form.Load event, or optionally the Form.Activate or Form.Shown events.
To understand the difference and which one suits you best, see this:
https://learn.microsoft.com/en-us/dotnet/desktop/winforms/order-of-events-in-windows-forms?view=netframeworkdesktop-4.8
Even though this would be a better approach, you still have the issue that the code is blocking the UI thread.
So then you need to look at using other methods to avoid this.
There are different ways to do this, but one is to use a backgroundworker.
//Initialise the worker and set the worker method
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += bw_DoWork;
//Start the worker
bw.RunWorkerAsync();
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
//Put your myMethod code here
}
See this for more details and the full capability of the backgroundworker and better examples:
https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.backgroundworker?view=net-6.0
Related
I'm trying to create my own chat app as a school project.
I have almost everything ready, connected with DB, backend. The only thing that is weighing me down right now is adding a TCP Server to the project for communication between Clients.
It's not supposed to be anything big, so just short code, plus I don't have that much experience with TCP in C#.
The code works, but the problem is that the Application/Window doesn't appear.
I suspected that the problem might be in the MainWindow() constructor due to the infinite loop (this was also confirmed here on SO). Unfortunately I don't know how to fix it anymore. I first had the server as a separate class, but I ran into this problem. So I tried implementing it directly in the class, or breaking the connection after shutting down the application.
public partial class MainWindow: Window {
private TcpListener myServer;
private bool isRunning;
public MainWindow() {
InitializeComponent();
myServer = new TcpListener(IPAddress.Any, 65525);
myServer.Start();
isRunning = true;
LoopServer();
}
private void LoopServer() {
while (isRunning) {
TcpClient client = myServer.AcceptTcpClient();
Thread thread = new Thread(new ParameterizedThreadStart(LoopClient));
thread.Start(client);
}
}
private void LoopClient(object obj) {
TcpClient client = (TcpClient) obj;
StreamReader reader = new StreamReader(client.GetStream(), Encoding.UTF8);
StreamWriter writer = new StreamWriter(client.GetStream(), Encoding.UTF8);
MessageBox.Show("Connected bro!");
writer.Flush();
bool clientRunning = true;
while (clientRunning) {
string data = reader.ReadLine();
MessageBox.Show(data);
writer.Flush();
}
}
}
An infinite loop is okay for a server to be running in. Generally, you can start up the server (1st application). The clients (different application) can connect to it and then process messages and broadcast them to all the clients appropriately.
Super simple example: Build Chat in C#
Alternatively you can try an event based approach to the TCP listener.
I'm having trouble making a simple test app that uses NetMQ to receive data from an established network. I'd like to eventually do things with this data, but for now I just need to get basic receiving working. The code is below:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
textOut.Text = "";
var utf8 = new UTF8Encoding();
using (var client = new SubscriberSocket())
{
client.Options.ReceiveHighWatermark = 1000;
client.Connect("tcp://eddn.edcd.io:9500");
client.SubscribeToAnyTopic();
while (true)
{
var bytes = client.ReceiveFrameBytes();
var uncompressed = ZlibStream.UncompressBuffer(bytes);
var result = utf8.GetString(uncompressed);
textOut.Text += result;
//Console.WriteLine(result);
Thread.Sleep(10);
}
}
}
}
When I run this, I see it is doing things in the performance monitor, but the window doesn't come up.
Before I added the NetMW code, the window displayed just fine so I don't think it is a problem with window visibility or anything like that. Any advice on what's going wrong here and how it might be fixed would be greatly appreciated.
Your immediate problem is you have a tight loop.
This:
while (true)
{
var bytes = client.ReceiveFrameBytes();
var uncompressed = ZlibStream.UncompressBuffer(bytes);
var result = utf8.GetString(uncompressed);
textOut.Text += result;
//Console.WriteLine(result);
Thread.Sleep(10);
}
Will run forever.
This is a bad thing.
That loop is running on the UI thread.
This is the thread that does everything.
That includes showing your window.
This problem is compounded by the fact you put that tight loop in your main window constructor.
Don't put substantial code in any UI object constructor. When it fails your ui object will not be constructed.
If that code really needs to loop forever then your socket reading code should be run on a background thread.
That aspect of the question is netmq specific rather than wpf but I would have thought you can open a socket and subscribe a handler which will act as data is received.
I have a simple TCP server based on the TcpListener. Since I want to use it in a Windows Form application I made it run in a separate thread as follows:
public void Start() {
this.serverThread = new Thread(new ThreadStart(this.ThreadProcess));
this.serverThread.Name = "Tcp-Server";
this.serverThread.Start();
}
protected void ThreadProcess() {
try
{
IPAddress ipAd = IPAddress.Parse("169.254.42.86");
this.listener = new TcpListener(ipAd, this.port);
this.listener.Start();
Socket mySocket = this.listener.AcceptSocket();
while (true)
{
if (mySocket.Connected)
{
byte[] RecvBytes = new byte[8192];
int byteNo = mySocket.Receive(RecvBytes, RecvBytes.Length, 0);
ASCIIEncoding asen = new ASCIIEncoding();
mySocket.Send(asen.GetBytes("srv reply msg"));
}
else
{
WriteLine("socket not connected.");
}
}
}
finally {
StopListener();
}
}
If I use this server in a console application as:
static void Main(string[] args)
{
try
{
int port = 8001;
Server server = new Server(port);
server.Start();
while (true) {
//server is running in separate thread
}
...
everything works as expected. However, when I try to include it in a Windows-Form Application that starts the server when a button is clicked, the code doesn't work any more. The server thread is being launched, but it doesn't accept any sockets.
Is there something that I am missing? I have been searching high and low on google without result...
Thanks for any help!
Not really an answer but too much to type in the comments:
The easiest way to debug this issue is to simply call the ThreadProcess() method in the same thread:
public void Start() {
ThreadProcess();
//this.serverThread = new Thread(new ThreadStart(this.ThreadProcess));
//this.serverThread.Name = "Tcp-Server";
//this.serverThread.Start();
}
You can then step through your code to see what happens. As soon as you hit the this.listener.AcceptSocket(); line your application will block, but you should be able to connect to it.
Usually the problem is something silly everyone overlooks like the Start() method not being called.
So, I have this game, written in Unity, which is supposed to receive data in real-time over UDP. The data will be coming over wireless from an android device, written in Java, while the Unity program is written in C#. My problem is, whenever I try to declare a UdpClient object, and call its Receive() method inside the Update() method of Unity, the game hangs. Here's the code that I am trying to put inside my Update() method -
UdpClient client = new UdpClient(9877);
IPEndPoint receivePoint = new IPEndPoint(IPAddress.Parse("192.168.1.105"), 9877);
byte[] recData = client.Receive(ref receivePoint);
But it's causing the game to hang.
I then tried a different approach - I tried to receive the data in a separate thread. Works like magic if all I have to do is receive the byte array. No issues. Except that I also need the data received to be used as parameters to functions used in the actual game (for now, let's just say I need to display the received data bytes as a string in the main game window). But, I do not have knowledge of how cross-threading works in Unity. I tried this -
string data = string.Empty;
private IPEndPoint receivePoint;
void OnGUI()
{
GUI.Box(new Rect(20, 20, 100, 40), "");
GUI.Label(new Rect(30, 30, 100, 40), data);
}
void Start()
{
LoadClient();
}
public void LoadClient()
{
client = new UdpClient(9877);
receivePoint = new IPEndPoint(IPAddress.Parse("192.168.1.105"), 9877);
Thread startClient = new Thread(new ThreadStart(StartClient));
startClient.Start();
}
public void StartClient()
{
try
{
while (true)
{
byte[] recData = client.Receive(ref receivePoint);
System.Text.ASCIIEncoding encode = new System.Text.ASCIIEncoding();
data = encode.GetString(recData);
}
}
catch { }
}
But my program hangs if I try the above. So, what exactly am I missing here?
The reason it hangs for you is because that's the way Receive is defined. It blocks your current code until there is data available on the network connection (i.e. the underlying socket). You are correct that you should use a background thread for that.
Please note though, that creating threads in your game object scripts can be dangerous business in case you for example attach the script to multiple objects at the same time. You don't want multiple version of this script running at the same time because they would all try to bind to the same socket address (which won't work).
You also need to pay attention to closing down the threads if the game object dies (this is not automatically done in C# - you have to stop threads).
That said, when you are using multiple threads you need to ensure thread safety. This means that you need to protect the data so that you cannot read it while it is being written to. The simplest way to do this is to use C# locks:
private readonly Object _dataLock = new Object();
private string _sharedData = String.Empty;
void OnGUI()
{
string text = "";
lock (_dataLock)
text = _sharedData;
}
void StartClient()
{
// ... [snip]
var data = Encoding.ASCII.GetString(recData);
lock (_dataLock)
_sharedData = data;
}
Note that locks can hurt performance a bit, especially if used frequently. There are other ways to protect data in c# that are more performant (but slightly more complex). See this guideline from Microsoft for a few examples.
So, I'm pretty new to all this network programming, and I have a few questions...
I'm building a client-server chat application, wherein the server is running, the client(s) connect(s) to the server, and then when a client sends a message to the server, the server relays it to all the clients. The server is a console application, and the client is a Windows Form Application.
The error I'm getting is in my client, at the very top of my form, I have a textbox to take in a user's name and a button to "submit" it and connect to the server with that username.
Anyways, this is my button connect code:
private void btnConnect_Click(object sender, EventArgs e)
{
readData = "Connecting to chat server...";
msg();
try
{
sck_client.Connect("127.0.0.1", 8888);
sw = new StreamWriter(sck_client.GetStream());
string toSend = txtUsername.Text;
sw.Write(toSend);
sw.Flush();
chatThread = new Thread(GetMessages);
chatThread.Start();
}
catch (Exception ex)
{
readData = ex.ToString();
msg();
}
}
msg() quite simply takes the value in readData and prints it to the screen (in a richtextbox). sw is a streamwriter that has been declared publicly, outside of the method, so is sck_client (a TcpClient) and chatThread (a Thread).
Basically, the issue is, when I run my program and try to connect, it throws Exception ex, as though it cannot connect. It throws a NullReferenceException with the text:
System.NullReferenceException: Object reference not set to an instance
of an object. at Chat_Client.Main.btnConnect_Click(Object sender,
EventArgs e) in filepath\Chat_Client\Main.cs:line36
That occurs even when my server is running and listening to port 8888. So, what should I do to fix it?
If you need any more of my code to solve the problem, let me know in a comment and I'll post it.
To show where the code is instantiated:
public partial class Main : Form // new class for the form itself
{
// all of these are declared outside any method:
TcpClient sck_client = default(TcpClient);
Thread chatThread = default(Thread);
string readData = null;
StreamWriter sw = default(StreamWriter);
StreamReader sr = default(StreamReader);
...
Ok, this line is your problem:
TcpClient sck_client = default(TcpClient);
specifically:
default(TcpClient);
default() will return the default value for a given type. If the type is a reference type (eg. class), then it will return null. If the type is a value type (eg. int) then it will attempt to set it to 0.
The default keyword does NOT create a new instance of the the class for you, you need to the use the new keyword for that.
I would seriously be reading this: http://msdn.microsoft.com/en-us/library/fa0ab757.aspx
TcpClient sck_client = default(TcpClient);
...
sck_client.Connect("127.0.0.1", 8888);
at some point, you will need to give it a value other than null (the default for TcpClient is null). Also, you probably don't need a StreamWriter just to send a string - I'd look at using Encoding (to get the bytes; typically UTF8), and a length-prefix of the size (in bytes).