I am creating a little game client that will end up connecting to a server to gather some information on available games to play, how many players are playing, and all kinds of other stuff that you can imagine it ought to do.
My difficulties come in finding an effective way in dealing with the connect/retry connect sequence upon first loading.
I imagined my client would follow this process in trying to connect:
Client application executed
Try to establish connection
If connection successful gather information - If not successful proceed to step 4
Display a new dialog/form that prompts the user that a connection is trying to be established
Loop till a connection has been established
I have been questioning my methods in trying to follow this sequence. I question if it is the right/most effective way to connect as well as to why my form I display in step 4 isn't working?
try
{
sock.Connect(authenServerEP);
// Once connected show our main client window
this.Show();
// Create the LoginForm once a connection has been established and display
LoginForm loginForm = new LoginForm();
loginForm.ShowDialog();
if (false == loginForm.Visible)
{
loginForm.Dispose();
}
}
catch (SocketException firstConnectException)
{
// Load retrying connection form
EstablishingConnectionForm establishingConnectionForm = new EstablishingConnectionForm();
establishingConnectionForm.Show();
bool connected = false;
// Loop until we are connected
while (!connected)
{
try
{
sock.Connect(authenServerEP);
connected = true;
establishingConnectionForm.Dispose();
}
catch (SocketException retryConnectException)
{
// Pass and retry connection
}
}
} // end catch (SocketException firstConnectException)
As you can see I am catching the SocketException that is raised when there is a problem connecting to the server (such as the server isn't running). I then go on to try to continuously loop till a connection is established. I dunno if I ought to be doing it this way. Are there better ways to do this?
Also when I display establishingConnectionForm with Show() it doesn't look like it all of the forms/tools initialize (initialize could be misleading). The Label that is on the form is just shaded out in white as opposed to having its text displayed. Not only that but it seems like I can't select the form/dialog and actually move it around. It sits there with the "Thinking/Working" mouse icon. Now I presume this is because I am looping trying to reconnect and its blocking because of this (I could be wrong on the blocking?). Can this problem be solved with multithreading? If so do I need to multithread? Is there an easier way to show my form/dialog and be able to interact (IE movie it around and close it with the 'X' in the upper right corner) with it while I still try to reconnect?
Thanks a bunch. I really appreciate you reading this post and am grateful for this community. :D
Just an example below where I would handle any continuation logic in the catch and either break out or continue inside the while loop.
Andrew
while (!connected)
{
try
{
sock.Connect(authenServerEP);
connected = true;
establishingConnectionForm.Dispose();
}
catch (SocketException retryConnectException)
{
//Optional - add some wait time may be 5 seconds i.e. "trying again in 5 seconds"
//System.Threading.Thread.Sleep(5000);
//Here check the number of attempts and if exceeded:
if(numberOfTimes == 5)
{
break;
}
else
{
numberOfTimes++;
continue;
}
}
}
Related
I'm writing a Connect-Four game in C#, and now want to include the possibility to play games online using TCP. Each instance of the game exe should work as both a server, in order to listen to incoming game invitations, and a client, to send said invitations. Of course, only one at a time is important.
I have read and watched a few C# tutorials on this (namely Jeff Chastine's tutorial 22) and I understand the basics of network communication. After getting past a few permission-errors, fixed by executing as administrator, I am now running into two issues.
1) When I try connecting from a machine on the same network, I always get an error saying the desired server did not respond to the request. When I enter the debugger, the program is stuck at the .AcceptTcpClient call (as if no connection has been attempted). I understand that this is a blocking call, but the code should continue when a connection is attempted. I have not tried connecting two machines in different networks, as I have only one network available.
2) This one is a rather minor issue regarding threading: even though I call listenerThread.Abort() when I close the application, the thread does not stop. I do not have too tight a grip on threads in C#, so I assume this problem is a rather easy fix.
Initialisation of listener and listenerThread
listenerThread = new Thread(ListenForInvites);
listener = new TcpListener(Dns.Resolve("localhost").AddressList[0], setting.port);
client = new TcpClient();
The method for listening to incoming connections
private void ListenForInvites()
{
try
{
listener.Start();
TcpClient enemyClient = listener.AcceptTcpClient(); // the call where it gets stuck even if someone connects
onlineSr = new StreamReader(enemyClient.GetStream());
onlineSw = new StreamWriter(enemyClient.GetStream());
onlineSw.WriteLine($"ACCEPT {player.name} {player.color.R} {player.color.G} {player.color.B}"); // I am using my own protocol, not HTTP (no clue if this is a horrible idea)
HandleConnection().Wait();
}
catch (Exception e)
{
MessageBox.Show(e.Message, "Error");
}
}
The method for attempting the connection
public void SendInvite(string ip)
{
try
{
string[] ipSplit = ip.Split(':');
client.Connect(ipSplit[0], Convert.ToInt16(ipSplit[1]));
onlineSr = new StreamReader(client.GetStream());
onlineSw = new StreamWriter(client.GetStream());
onlineSw.WriteLine($"INVITE {player.name} {player.color.R} {player.color.G} {player.color.B}"); // player is an instance variable
onlineSw.Flush();
HandleConnection().Wait();
}
catch (Exception e)
{
MessageBox.Show(e.Message, "Fehler");
}
}
What am I doing wrong? Any help is appreciated.
I have an issue when there is an exception in a block of code that uses a lock. I am reading and writing to a serial port and there are several different threads that need access to the same serial port. This is managed by a lock. I have no issues except if the serial port stops working. This can happen since the software controls an RF transmitter and occasionally the rf can cause usb to serial ports to stop functioning. If you then attempt to write to the port you will get a write timeout. I tried handling this from a try - catch exception handler. However, the program locks hard at that point and has to have the task killed. I am not sure if this is coming from the exception or the message box I am trying to display since it could result from a background thread. Here is the code:
lock (_object)
{
try
{
if (portOpened)
{
port.Write(data);
}
else
{
MessageBox.Show("The radio is not connected. Please select a ComPort in the settings dialog");
}
}
catch (Exception x) //this will capture a write exception.
{
MessageBox.Show("The program is unable to write to the serial port. Select OK to close the program";
Application.Exit();
}
finally
{
}
}
Thanks for any help
If you want to force to exit the app, Application.Exit is not a good candidate, as it simply pushes the Close request on message queues of all threads, but does not force anything. If you want to stop app at any cost, use Environment.Exit(exitCode), or may be even better Environment.FailFast, with specified exception so it will be logged into the system's log: convenient for future investigations.
I am experiencing a weird issue where the timeout remaining for a connection attempt seems to be persisting through multiple attempts.
I have a simple window where connection information is entered, with a connect and cancel button.
When the user hits connect, the following code executes:
DisableControls();
if((bool)AutoAuthenticated.IsChecked)
{
((MainWindow)Owner).myConnection = new System.Data.SqlClient.SqlConnection
("server="+ServerName.Text + ";"+
"Trusted_Connection=yes;" +
"database="+DatabaseName.Text + ";" +
"connection timeout=3");
}
else
{
((MainWindow)Owner).myConnection = new System.Data.SqlClient.SqlConnection
("user id="+UserName.Text+";" +
"password="+Password.Password+";" +
"server="+ServerName.Text+";" +
"Trusted_Connection=no;" +
"database="+DatabaseName.Text+";" +
"connection timeout=3");
}
await ConnectToServer();
This is the ConnectToServer function:
private async Task ConnectToServer()
{
//using (((MainWindow)Owner).myConnection)
//{
await ((MainWindow)Owner).myConnection.OpenAsync();
//}
}
The timeout property is small right now for the purposes of testing.
Anyway, if the user hits the cancel button whilst connecting:
private void Cancel_Click(object sender, RoutedEventArgs e)
{
if (((MainWindow)Owner).myConnection != null &&
((MainWindow)Owner).myConnection.State ==
System.Data.ConnectionState.Connecting)
{
((MainWindow)Owner).myConnection.Close();
EnableControls();
}
else
{
this.Close();
}
}
Now, if I enter in bogus details and leave it to timeout, then I catch the exception with 'The network path was not found.'.
If I try and connect again after this (or maybe the one after the next attempt depending on how quick I was to hit the cancel button), it times out almost instantly after hitting the connect button, without waiting the amount of time it was supposed to.
I'm not sure what I'm doing wrong here, I've tried looking in to resetting the SqlConnection object, but I thought the setting of it to a new SqlConnection each time I hit connect should be doing this already?
I found out what I was missing. Even when closing the connection, disposing of the object, keeping it all in a using statement, the issue persisted because there was another element that I was unaware of - the connection pool.
I still have to do some reading on this, but basically it reuses old connection information and so on to save on resources, etc.
There's more information here, but in case this helps someone else with similar issues, just call the ClearPool() function when you close the connection:
Example (in my exception handling code, and after I call Close()):
System.Data.SqlClient.SqlConnection.ClearPool(((MainWindow)Owner).myConnection);
Obviously from a resource usage perspective, it would probably be best to call that function only when you don't need to reuse the connection, but that said, I still need to read up on this so don't take my word for it!
I have buggy code and I don't know where or what is the fault.
I am writing an application for a customer. During the splash screen the app checks if Mysql is running to be able to connect to it later. If mysql is on, the app continues booting. If mysql is not running I start it and re-check again.
Initially, I was finding the mysql pid, but for some reason I can't get it without using unmanaged code.
So I found another way in xampp source code and I decided to use it.
Running the app under vstudio debugger stepping or stopping in a breakpoint works perfectly, but if run without stepping, the app boots mysql server but canĀ“t detect it and eventually the application stop (I don't want the app continue loading if database fails).
This behavior has led me to think that one or more variables are disposed at runtime before I can use it again.
I don't know how solve this issue and need a hand.
EDIT: The issue was mysql was not started yet running the app without interruption
As Jan & SWEKO said. Adding some delay works perfectly
The splash screen Load code.
// App booting tasks
void Load()
{
// License validation ok
Boolean licensecheck = BootChecks.LicenseCheck();
if (! licensecheck)
{
MessageBox.Show("License Error Conta ct Technical Support","Error",MessageBoxButtons.OK,MessageBoxIcon.Stop);
Application.Exit();
}
bar.Width += 10; // feed progress bar ( it's a custom drawn label )
this.Refresh(); // update form to paint it
Application.DoEvents(); // process all pooled messages
// Mysql check
Boolean dbcheck = BootChecks.DbCheck();
// THE ISSUE IT'S HERE RUNNING WITHOUT STEPPING , ALWAYS FIRES THE ERROR
if ( ! dbcheck )
{
MessageBox.Show("Can't init Mysql. Contact Technical Support", "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
Application.Exit();
}
bar.Width += 10;
this.Refresh();
Application.DoEvents();
// more stuff
}
Database check code
public static bool DbCheck()
{
Boolean norun = MysqlController.CheckMysqlIsRunning(Constants.dbpidfile);
// check if running
if ( norun ) return true;
// if not running, I start it
MysqlController.StartMysql(Constants.dbexe,Constants.dbopts);
Boolean rerun = MysqlController.CheckMysqlIsRunning(Constants.dbpidfile);
// if really running all it's ok
if ( rerun ) return true;
// really a fault
return false;
}
Real mysql check
comment: this way was found on xampp package. To know if mysql it's running find mysql pid file, and open a named event. if right definitively mysql it's running.
public static Boolean CheckMysqlIsRunning(String pathtopidfile)
{
try
{
Int32 pid;
using ( StreamReader sr = new StreamReader(pathtopidfile) )
{
pid = int.Parse(sr.ReadToEnd());
}
IntPtr chk = OpenEvent(SyncObjectAccess.EVENT_MODIFY_STATE, false,
String.Format("MySQLShutdown{0}", pid.ToString()));
if ( chk != null ) return true;
return false;
}
catch (Exception) { return false;}
}
public static void StartMysql(String path, String aargs)
{
// All ok. Simply spawn a process
}
You have to code some kind of loop. You start the mysql process and when you check immediately after is, the process is still not there and you return false.
Try something like this:
// if not running, I start it
MysqlController.StartMysql(Constants.dbexe,Constants.dbopts);
// wait 10 seconds max.
int timeout = 10;
bool mySqlIsRunning = false;
while(!MysqlController.CheckMysqlIsRunning(Constants.dbpidfile)) {
// wait a while
Thread.Sleep(1000);
if (timeout-- == 0) {
// timeout error
// show message to user ...
}
}
// here mysql is running or your timeout is expired.
I think the problem might be that you spawn a background process that is not finished when you run the check.
When you are debugging, MySQL has enough time to start in the time it takes you to go from
MysqlController.StartMysql(Constants.dbexe,Constants.dbopts);
to
Boolean rerun = MysqlController.CheckMysqlIsRunning(Constants.dbpidfile);
However, that might not be the case when you are running the app for real. As a simple test, try adding a simple Thread.Sleep(2000) to wait a couple of seconds before the running the check again.
IMHO its bad form to have a method say it will do a check, then also do an initialization. Break out the code of the check into two. Then do the initialization in the main code after the check. Hold on to the references to the database by having them held as properties on the form.
I have a TCP Tunnel in C#. I need to open and close the tunnel which is my app between a server and a client. I'm using this to close the data connection to test out another app. I have to use particular ports.
On the second, third, nth connection depending on how long I wait to reconnect, I receive a 10048 error code - "Address already in use" when binding my socket. When closing the sockets, I do perform ShutDown.Both and Close in hopes of clearing out the ports, but when I do a netstat in a command prompt I still find the ports held in TIME_WAIT. I've also set the sockets to no linger. Lastly I tried to make a loop to check the status of the port, but it ends in a somewhat endless loop. I'm thinking it's that 4 minute TIME_WAIT rule.
I have a function to display a nestat query and I find that when I run that and check until the port goes from ESTABLISHED and into TIME_WAIT that I can bind, but when I use the same data from this query to bind on a loop when the status reaches TIME_WAIT, I get a 10048. Is there a brief moment in time allowed by my button click that allows me to bind? Is there a state between TIME_WAIT and ESTABLISHED I'm hitting in the loop and not when I do it with button clicks? I read TIME_WAIT should stop me from binding altogether, but this does not appear to be true. Can anybody explain this?
I apologize to you code lovers. Not thinking this will change anything though. I just need a better understanding of port states.
public bool CheckAvailablePorts()
{
int temp=0;
bool availPort= true;
m_config = new AppConfig();
if (!m_config.initialize())
{
System.Diagnostics.Debug.WriteLine("Error loading configuration file. Exiting...");
return false;
}
else
{
//checking through all the ports that have been set to connect on
foreach (ProxyConfig cfg in m_config.m_proxyConfigs)
{
availPort = true;
temp = cfg.localEP.Port;
DataView dv = FindEstablishedSockets();//returns netstat query
foreach (DataRowView rowView in dv)
{
DataRow row = rowView.Row;
if ((Convert.ToInt32(row["Local Port"].ToString()) == temp) && (row["Status"].ToString().Equals("Established")))
{
System.Diagnostics.Debug.WriteLine("Port: " + temp + " is still locked");
availPort = false;
break;
}
}
}
return availPort;
}
}
//snippet out of a bigger function which checks for availability and then sleeps if false and runs again
bool temp = false;
while (!temp)
{
temp = monitor.CheckAvailablePorts();
System.Threading.Thread.Sleep(2000);
}
System.Threading.Thread.Sleep(3000);
monitor.startApplication(); //starts all the binding
You need to be a bit more specific as it's hard to know what you are doing. Shorter text and a code sample would help.
I need to open and close connections and then reopen them again
That should not be a problem if it's in the client. If it's server-side, please explain why.
The config file on the server is looking for a particular port, so when I reconnect I need the same port open again
What do you mean? If you mean the listening port: You should never close the listener socket. If you do not want to accept more than one socket, simply do not call Accept again until the client socket have been disconnected.
I read TIME_WAIT should stop me from binding altogether, but this does not appear to be true.
There is an option you can use that will allow you to bind a local port that is in TIME_WAIT. This is very useful to ensure you don't have to wait 4 minutes after killing a server before restarting it.
int flag = 1;
sockfd = socket(...);
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
bind(...);
Before closing a socket, you must read all the data sent by its peer, otherwise it will stay in TIME_WAIT to ensure a new socket will not read data intended for the previous (closed one). You could also try the no lingering option of the socket.
Details: http://msdn.microsoft.com/en-us/library/windows/desktop/ms738547%28v=vs.85%29.aspx