thanks in advance for anything.
Im making a server-client program, in which the server(application) creates a server and the client connects to it, i will also have a textbox and a button on the server application and whenever i write something on that textbox and press the button, it will send to the client application(there is only a textbox in this application, the only thing this application does is receive strings from the server application).
I think it works, kinda, but not the way i want it.
I can make the connection and also send and receive the information from the textboxs, but only if i run the server application first(to create the server). The problem is that if i dont run the server application first(to create the server), the client application won't connect, or even try to.
Example of "Error"(i guess you can call it an error):
If i run the client application first and then the server application, the client application just won't connect to the server that the server application created, i made a loop that basically verifies if the client is cnnected, if it is then it starts receiving the information, if not(else) waits for 3 seconds and tries to reconnect again. but when it tries to reconnect it doesnt work.
Any ideas?
CODE IN C#:
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) //connect to server
{
client = new TcpClient();
IPEndPoint IP_End = new IPEndPoint(IPAddress.Parse("192.168.254.34"), 123); // sincronizacao do IP com a porta
try
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IAsyncResult result = client.BeginConnect(IPAddress.Parse("192.168.254.34"), 123, null, null);
bool success = result.AsyncWaitHandle.WaitOne(3000, true);
while (success)
{
if (client.Connected)
{
STW = new StreamWriter(client.GetStream());
STR = new StreamReader(client.GetStream());
STW.AutoFlush = true;
backgroundWorker1.RunWorkerAsync(); // Começar a receber dados em background
backgroundWorker1.WorkerSupportsCancellation = true; // possibilidade de cancelar o fio
}
else
{
int milliseconds = 3000;
Thread.Sleep(milliseconds);
MessageBox.Show("swag do elias!");
client.Connect(IP_End);
}
}
}
catch (SocketException exception)
{
MessageBox.Show("O erro é:", exception.Source);
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) // Receber dados
{
while(client.Connected) //enquanto o cliente tiver conectado vai ler o que servidor diz em chat
{
try
{
receive = STR.ReadLine();
this.textBox2.Invoke(new MethodInvoker(delegate () { textBox2.Text=(receive + "\n\r"); }));
receive = "";
}
catch(Exception x)
{
MessageBox.Show(x.Message.ToString());
}
}
}
}
}
If the server isn't running yet, then success is always going to be false as a result of this line:
bool success = result.AsyncWaitHandle.WaitOne(3000, true);
Since success will always be false, the code inside of your while(success) block will never be executed.
Rearranging your code to something like this might be helpful:
client = new TcpClient();
bool success = false;
while (success == false)
{
try
{
IAsyncResult result = client.BeginConnect(IPAddress.Parse("192.168.254.34"), 123, null, null);
success = result.AsyncWaitHandle.WaitOne(3000, true);
}
catch (Exception ex)
{
success = false;
MessageBox.Show("error connecting: " + ex.Message + " : " + ex.StackTrace);
}
}
// NOW, by the time you reach this point, you KNOW that success == true and that you're connected, and you can proceed with the rest of your code
STW = new StreamWriter(client.GetStream());
STR = new StreamReader(client.GetStream());
STW.AutoFlush = true;
backgroundWorker1.RunWorkerAsync(); // Começar a receber dados em background
backgroundWorker1.WorkerSupportsCancellation = true; // possibilidade de cancelar o fio
Related
I have a problem in my hands.
I have a program in which the client (form1) has to try to reconnect whenever it can not connect to the server.
The loop that I have to do the reconnection is inside the Fomr_load so that the reconnection is automatic.
But the problem is that the application does not open until form_load is complete.
Who knows where I'm goin tell me please
private void Form1_Load(object sender, EventArgs e)
{
Client = new TcpClient();
IPEndPoint IP_End = new IPEndPoint(IPAddress.Parse("192.168.254.38"), 100);
try
{
Socket Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Client.Connect(IP_End);
if (Client.Connected)
{
STW = new StreamWriter(Client.GetStream());
STR = new StreamReader(Client.GetStream());
STW.AutoFlush = true;
backgroundWorker1.RunWorkerAsync();
backgroundWorker1.WorkerSupportsCancellation = true;
}
else
{
reconnect();
}
}
catch (SocketException)
{
reconnect();
}
}
private void reconnect()
{
try
{
IPEndPoint IP_End = new IPEndPoint(IPAddress.Parse("192.168.254.38"), 100);
Client.Connect(IP_End);
STW = new StreamWriter(Client.GetStream());
STR = new StreamReader(Client.GetStream());
STW.AutoFlush = true;
backgroundWorker1.RunWorkerAsync();
backgroundWorker1.WorkerSupportsCancellation = true;
}
catch (SocketException)
{
reconnect();
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (Client.Connected)
{
try
{
receive = STR.ReadLine();
label1.Invoke(new MethodInvoker(delegate () { label1.Text = (receive + "\n\r"); }));
receive = "";
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
}
}
Have a boolean variable that you set to true once you connect successfully and then check that as well before calling reconnect(), so your loop should run once, set connectedSuccessfully = true, then next time it runs it will see that it's true and skip over the call to reconnect(). You probably also want to add a timer to maybe try once again after 1 second, then try again in 5 seconds, then again in 10 etc etc.
I'm creating a game in which I use TCP/IP connection. The problem is that I'm using .Invoke to help me receive and send message.
The program goes like this: I'm my first window, i'm starting and connecting to the server like this :
{
TcpListener listener = new TcpListener(IPAddress.Any, this.port);
listener.Start();
try {
this.client = listener.AcceptTcpClient();
gameWindow = new GameWindow(this.client, true);
gameWindow.StartGame();
}
}
then i'm connecting to it like this:
{
IPEndPoint ipEnd = new IPEndPoint(this.serverIP, this.port);
{
try {
client.Connect(ipEnd);
if (client.Connected) {
gameWindow = new GameWindow(this.client, false);
gameWindow.StartGame();
}
}
}
The constructor for gameWindow (which is a form) looks like this:
public GameWindow(TcpClient thisClient, bool isServer)
{
InitializeComponent();
this.client = thisClient;
this.reader = new StreamReader(thisClient.GetStream());
this.writer = new StreamWriter(thisClient.GetStream());
this.writer.AutoFlush = true;
}
I must wait for the server to send a message to the client, and then start the client ( I have a function .startGame() that uses .ShowDialog() and creates some pictureBoxs)
But nowhere I can get my handle created. I've tried to put this.createHandle() (read about it here) into GameWindow_Load but still not works. If I try to send a message with:
workerSendData.RunWorkerAsync(); I get:
Additional information: Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
What can I do to get my handler created? Using Thread.Sleep will sleep my whole UI, which does not work (a "solution" found on the internet)
My code for sending message :
private void workerSendData_DoWork(object sender, DoWorkEventArgs e)
{
if (client.Connected) {
this.writer.WriteLine(this.toSend); // aici trimitem datele.
// de modificat : aici vom adauga in lista noastra miscarile.
this.Invoke(new MethodInvoker(delegate () { MessageBox.Show("Me:" + this.toSend + "\n"); }));
}
else {
MessageBox.Show("Send failed");
}
workerSendData.CancelAsync();
}
My code for receiving data:
private void workerReceiveData_DoWork(object sender, DoWorkEventArgs e)
{
while (client.Connected) {
try {
this.received = this.reader.ReadLine();
this.myTurn = true;
this.Invoke(new MethodInvoker(delegate () {
MessageBox.Show("This has been received: " + this.received);
/*this.tbReceive.AppendText("You:" + this.received + "\n");*/
}));
this.received = "";
}
catch (Exception x) {
MessageBox.Show(x.Message.ToString());
}
}
}
It seems that you cannot invoke an action before the Window is fully initialized and loaded. Assuming you are working in Windows Forms, there is a solution provided by #Greg D on this question, but it doesn't be to be the safest way to go.
I would suggest that you try to find a way to start the worker only after the window is loaded (for example using the Loaded event), so that the handle is definitely ready and this situation does not occur.
i do have an embedded board (mini/tiny 210)
and i did try building an application which uses system.socket and system.socket.net in C# ( vs2005 - wince5 device application but i do have wince 6 on my device!! )
my purpose is to send and receive data bytes using Ethernet. for sending , well there is no problem but receive does need multitasking.
i should start a task so it can listen to the port if there is any data upcoming but once i add thread part to my code the whole program crashes (dose not do that in pc x64 core i5) but in embedded board it will crash.
if i eliminate multi tasking i might lose some data when networkstream.read is not online or when networkstream.read is online and i'm waiting for data,which ends in program will not respond up until the timeout. here is some of my codes . hope it helps.
this code does work :
private void button_connect_Click(object sender, EventArgs e)
{
try
{
//Thread TH = new Thread(new ThreadStart(con));
//TH.Start();
con();
}
catch
{
MessageBox.Show("THREAD ERROR");
}
}
public void con()
{
try
{
cli = null;
cli = new TcpClient();
cli.Connect(IPAddress.Parse(textBox_ip.Text),Convert.ToInt32(textBox_port.Text));
st = null;
st = cli.GetStream();
button_connect.Enabled = false;
button_Close.Enabled = false;
button_disconnect.Enabled = true;
statusBar1.Text = "Connected to server";
//Thread rec = new Thread(new ThreadStart(recf));
//rec.Start();
}
catch
{
MessageBox.Show("Connection faild","Error");
statusBar1.Text = "Faild to connect to server";
}
this code dose not work :
private void button_connect_Click(object sender, EventArgs e)
{
try
{
Thread TH = new Thread(new ThreadStart(con));
TH.Start();
//con();
}
catch
{
MessageBox.Show("THREAD ERROR");
}
}
public void con()
{
try
{
cli = null;
cli = new TcpClient();
cli.Connect(IPAddress.Parse(textBox_ip.Text),Convert.ToInt32(textBox_port.Text));
st = null;
st = cli.GetStream();
button_connect.Enabled = false;
button_Close.Enabled = false;
button_disconnect.Enabled = true;
statusBar1.Text = "Connected to server";
//Thread rec = new Thread(new ThreadStart(recf));
//rec.Start();
}
catch
{
MessageBox.Show("Connection faild","Error");
statusBar1.Text = "Faild to connect to server";
}
}
as you can see i'm getting this crash while just one of my task is in the code the second task has been commented
i appreciate your help in advance
The crash is probably caused by updating UI elements from a secondary thread.
The con method reads a textbox and updates several buttons as well as a status bar, and this should only happen on the main application thread.
To verify whether this is the issue, you could simply comment out the lines in the con method that access UI elements (copy the textbox value to a member string before starting the thread, or just hard-code the IP address) and re-run the application.
Then to actually fix the problem you'll have to look into Control.Invoke.
It's a lot of irrelevant code to look through.. but pretty much it sends a packet and listens for a packet in return
if i comment the part out where it calls the ReceiveAuthPacket() method at the end of sending a packet, it will work and the label will turn blue.. but otherwise it will never activate turning the label blue and will instead turn the label red or green (depending on the returned packet).
basically im just using the label as an indicator of the status.. and no matter what i try i can't get it to turn blue because it seems to be waiting for all the code to be finished executing and it just won't work..
i even tried using data triggers in WPF and it still won't work.
any work arounds? i just don't get it..
private readonly UdpMessageAuthentication _msgAuth;
private void Button_Authenticate_OnClick(object sender, RoutedEventArgs e)
{
Label_Authentication.Content = "Attempting Authentication";
Label_Authentication.Foreground = new SolidColorBrush(Colors.Blue);
_msgAuth.SendAuthPacket(IPAddress.Parse(TextBox_IP.Text), TextBox_ClientID.Text);
}
public void SendAuthPacket(IPAddress ip, string userID)
{
_ip = ip;
_userID = userID;
if (_udpClient.Client == null)
_udpClient = new UdpClient();
//GSISClockRegRequest,<Client Id>,,1
string msg = string.Format("GSISClockRegRequest,{0},,1", _userID);
byte[] sendBytes = Encoding.ASCII.GetBytes(msg);
bool sent = false;
try
{
_label.Content = "Attempting Authentication";
_label.Foreground = new SolidColorBrush(Colors.Blue);
while (_label.Content != "Attempting Authentication")
{
//loop
}
_udpClient.Connect(_ip, 5001);
_udpClient.Send(sendBytes, sendBytes.Length);
Console.WriteLine("Sending {0} bytes. Message: {1}", sendBytes.Length, msg);
sent = true;
}
catch (Exception)
{
Console.WriteLine("UDP Auth Packet Failed to Send");
}
_udpClient.Close();
if (sent)
ReceiveAuthPacket(); //IF I COMMENT THIS OUT IT'LL WORK
}
private void ReceiveAuthPacket()
{
IPEndPoint e = new IPEndPoint(IPAddress.Any, 5001);
UdpClient u = new UdpClient(e);
u.Client.ReceiveTimeout = 3000;
Console.WriteLine("Listening for Messages: ");
try
{
Byte[] receiveBytes = u.Receive(ref e);
string receiveString = Encoding.ASCII.GetString(receiveBytes);
Console.WriteLine("Received: {0}", receiveString);
string errMsg = "";
if (AuthMessageParser.ParseMessage(receiveString, ref errMsg))
{
_label.Content = "Authentication Successful!";
_label.Foreground = new SolidColorBrush(Colors.Green);
}
else
{
_label.Content = "Authentication Unsuccessful: " + errMsg;
_label.Foreground = new SolidColorBrush(Colors.Red);
}
}
catch (Exception)
{
_label.Content = "Authentication Unsuccessful";
_label.Foreground = new SolidColorBrush(Colors.Red);
Console.WriteLine("UDP Auth Packet was NOT Received.");
}
u.Close();
}
Your UI thread is blocked by calls to things like _udpClient.Connect() and _udpClient.Send() (and the receives, too)
A workaround would be to leverage the task parallel library and perform communications asynchronously to avoid blocking the UI thread.
It will manage threads for you as long as you define tasks properly. Holler if you need an example.
protected void SomeButton_Click(Object sender, EventArgs e)
{
// Task off the work and do not wait, no blocking here.
Task.Run(PerformConnection);
}
private async Task PerformConnection()
{
// This method acts the way a thread should. We await the result of async comms.
// This will not block the UI but also may or may not run on its own thread.
// You don't need to care about the threading much.
var conn = await ListenerOrSomething.AwaitConnectionsAsync( /* ... */ );
// Now you have your result because it awaited.
using(var newClient = conn.Client())
{
var buffer = new byte[];
var recv = await newClient.ReceiveAsyncOrSomething(out buffer);
// Data received is not zero, process it or return
if(recv > 0)
newClient.Response = await ProcessRequest(buffer);
else
return;
}
}
I am writing an application to send/receive some data to and from a server. I need to make a connection before sending some data and need to keep it open so that user can send data continuously. The user can close the connection at any time by clicking on disconnect button. I created 2 buttons, one to connect and one to disconnect.
Code behind Disconnect button is as below:-
private void button1_Click(object sender, EventArgs e)
{
if (tcpclnt.Connected)
{
tcpclnt.Client.Disconnect(false);
stm.Close();
}
else
{
MessageBox.Show("Not Connected");
}
}
code behind connect button is as below:-
public ASCIIEncoding asen = new ASCIIEncoding();
public TcpClient tcpclnt = new TcpClient();
public NetworkStream stm;
private void Connect_Click(object sender, EventArgs e)
{
if (!tcpclnt.Connected)
{
tcpclnt.Connect("XX.XX.XX.XX", 5500);
MessageBox.Show("Connected to server");
stm = tcpclnt.GetStream();
string sysname = "000B0000" + SystemName.Text.ToString();
byte[] sys1 = asen.GetBytes(sysname);
sys1[0] = 0; sys1[1] = 0;
sys1[2] = 0; sys1[3] = 0xB;
sys1[4] = 0; sys1[5] = 0;
sys1[6] = 0; sys1[7] = 0;
try
{
stm.Write(sys1, 0, sys1.Length);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
MessageBox.Show("Error in Sending data");
}
if (stm.DataAvailable)
{
try
{
byte[] bb = new byte[600];
int k = 8;
k = stm.Read(bb, 0, bb.Length);
string value = ASCIIEncoding.ASCII.GetString(bb, 8, k - 8);
MessageBox.Show(value.ToString());
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
MessageBox.Show("Error in Reading data");
}
}
}
else {
MessageBox.Show("Already Connected");
}
}
Now, when I click on Disconnect button and again click on connect button, it's throwing an exception on tcpclient.connect line. I don't understand why or how can I solve it.
Not an expert on this topic, but I think a possible solution would be to gracefully close the connection using tcpclnt.Close(). If you don't do this or let the garbage collector do it ungracefully, then you can't reconnect (I think). Close the stream, then close the tcpclnt rather than disconnect.
tcpclnt.GetStream().Close();
tcpclnt.Close();
Also, don't use tcpclnt.Connected to check if there's a connection. Just simply Close it.
EDIT
The above doesn't work. I don't know how to reuse the socket. This is how I got it to work...
private void DisconnectButton_Click(object sender, EventArgs e)
{
tcpclnt.Close();
tcpclnt = new TcpClient();
}
You mentioned that re-instantiating the object creates additional threads. This might be true as I'm unsure how to test for this. I opened up the windows resource monitor and watched the thread count for the app and it didn't show an additional thread opening each time.
Your .Disconnect() call needs to have true as the parameter to allow reuse. You currently are telling the socket to disallow reconnection. See here for the documentation.