I've written a very complex multi-server IRC bot recently, and have encountered an issue..
I have stripped down the code as much as I could which can be viewed here.
My issue is that when I call the Disconnect() the connection is voided instead of disconnecting and closing the given server. It also just freezes the calling class instead of stopping the correct instance of the Class.
Any help or experience with a similar issue would be greatly appreciated.
Please include code if you can.
First off, you need to add a break so that this:
foreach (Connection connect in connections)
{
if (searching == true)
{
if (connect.SERVERID == ServerID)
{
connect.Stop();
isFound = true;
searching = false;
connections.Remove(connect);
}
}
}
Becomes:
foreach (Connection connect in connections)
{
if (connect.SERVERID == ServerID)
{
connect.Stop();
isFound = true;
connections.Remove(connect);
break;
}
}
Because you are modifying the collection, rather than using the searching == true clause. Much more efficient.
Next, I would change your thread run to look like this:
public void Run()
{
bool WhileOn = true;
NetworkStream stream;
string inputLine;
StreamReader reader;
try
{
using(TcpClient irc = new TcpClient(SERVER, PORT))
{
...
}
}
catch (ThreadAbortException)
{
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
Thread.Sleep(5000);
}
}
So that your connection gets properly disposed. You should do similarly for your stream.
And finally, I would add an Abort() call on your thread in the Stop function after a set timeout. If a TCP socket is blocked by the OS, however, I'm not sure if an abort call will interrupt it...
Related
I made a server-client program with auto connection.
But the program only works if I first start the server application because the client needs to connect.
My goal is for the client to check with a delay of 2 seconds if the server is already created.
I made a while statement for a trial and error cycle
try
{
int a = 1;
while (a == 1)
{
cliente.Connect(IP_End);
if (cliente.Connected)
{
connectRead();
a = 2;
}
else
{
while (!cliente.Connected)
{
int milliseconds = 2000;
Thread.Sleep(milliseconds);
cliente.Connect(IP_End);
MessageBox.Show(text);
if (cliente.Connected)
{
connectRead();
}
}
}
}
}
catch(SocketException se)
{
MessageBox.Show(se.Message);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
the error is :
No connection can be made because the target computer actively refused them 192.168.254.28:100
the method is here :
private void connectRead()
{
STW = new StreamWriter(cliente.GetStream());
STR = new StreamReader(cliente.GetStream());
STW.AutoFlush = true;
backgroundWorker1.RunWorkerAsync();
backgroundWorker1.WorkerSupportsCancellation = true;
}
Based on the code you almost got it right. I believe the "Connect" extension method should update the value within the client. If it does the way I'd do it would be to introduce a separate method that returns a boolean and it would help to simplify the code. For example:
private bool ConnectClient(SomeClient clientToConnect, IPAddress ipToConnectTo, int delay)
{
System.Threading.Thread.Sleep(delay);
clientToConnect.Connect(ipToConnectTo);
return clientToConnect.Connected;
}
try
{
bool successfulConnection;
while (!successfulConnection)
{
successfulConnection = ConnectClient(yourClient, "10.10.10.10", 2000);
}
}
catch
{
// ...
}
Without knowing more about errors or desired functionality, I can tell you will call connectRead(); twice if you hit the second loop. To fix this replace your second loop with this:
while (!cliente.Connected)
{
int milliseconds = 2000;
Thread.Sleep(milliseconds);
cliente.Connect(IP_End);
if (cliente.Connected)
{
connectRead();
a = 2;
}
}
EDIT:
I also took out the MessageBox because that seems unnecessary and will pause the program until you hit Ok on the MessageBox.
EDIT 2:
Question on actively refused connections
Question on determination of open port
The following code, despite apparently closing the UDP Socket, leaves it hanging and unable to reconnect to the same address / port.
These are the class variables I use:
Thread t_listener;
List<string> XSensAvailablePorts;
private volatile bool stopT_listener = false;
volatile UdpClient listener;
IPEndPoint groupEP;
I create and launch a new thread with a method which will handle the Socket connection and listening:
private void startSocketButton_Click(object sender, RoutedEventArgs e)
{
stopT_listener = false;
closeSocketButton.IsEnabled = true;
startSocketButton.IsEnabled = false;
t_listener = new Thread(UDPListener);
t_listener.Name = "UDPListenerThread";
t_listener.Start();
}
The method is the following (I use a time-out on the Receive in order to not leave it blocked if nothing is being sent on the socket and a Stop is being issued):
private void UDPListener()
{
int numberOfPorts = XSensAvailablePorts.Count();
int currAttempt = 0;
int currPort = 0;
bool successfullAttempt = false;
while (!successfullAttempt && currAttempt < numberOfPorts)
{
try
{
currPort = Int32.Parse(XSensAvailablePorts[currAttempt]);
listener = new UdpClient(currPort);
successfullAttempt = true;
}
catch (Exception e)
{
currAttempt++;
}
}
if (successfullAttempt)
{
//timeout = 2000 millis
listener.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 2000);
//Tried with and without, no change: listener.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
statusTB.Dispatcher.BeginInvoke((Action)delegate() { statusTB.Text = "Connected on port:" + currPort; });
groupEP = new IPEndPoint(IPAddress.Parse("143.225.85.130"), currPort);
byte[] receive_byte_array;
try
{
while (!stopT_listener)
{
try
{
receive_byte_array = listener.Receive(ref groupEP);
if (receive_byte_array.Length == 0 || receive_byte_array == null)
continue;
ParseData(receive_byte_array, samplingDatagramCounter);
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.TimedOut)
continue;
}
}
}
catch (Exception e)
{
Debug.Print(e.Message);
}
finally
{
if (listener != null)
{
listener.Client.Shutdown(SocketShutdown.Both);
listener.Close();
}
}
}
statusTB.Dispatcher.BeginInvoke((Action)delegate() { statusTB.Text = "Not Connected"; });
return;
}
I order the thread / socket to stop with this method:
private void closeSocketButton_Click(object sender, RoutedEventArgs e)
{
stopT_listener = true;
closeSocketButton.IsEnabled = false;
startSocketButton.IsEnabled = true;
t_listener.Join();
if (listener.Client != null)
{
listener.Client.Shutdown(SocketShutdown.Both);
listener.Close();
}
if (t_listener.IsAlive)
{
t_listener.Abort();
statusTB.Text = "Aborted";
}
else
statusTB.Text = "Not Connected";
}
Despite checking in debug that the socket has been closed, if I retry to connect to the same port, I am unable to do so because it raises a SocketException saying that only one usage of port/address is normally permitted.
I put code you provided in a simple form to run it and... I cannot directly reproduce your problem. I haven't send any data to the client though, but as far as I understand it shouldn't change anything as it's UDP and we're investigating (re)opening socket, not transmitting data.
When clicking Start/Stop buttons the socket is always properly opened and closed, reopening works as intended.
For me the only way to force the SocketException you mentioned was to introduce some obvious misuse of socket logic:
Run two instances of application and click Start in both.
Remove BOTH occurrences of Shutdown and Close (Stop doesn't close socket).
Running app, opening socket, closing the app without closing socket, running app again, trying to open socket.
Only changes I made in your code was removing ParseData(...) line and adding some ports to XSensAvailablePorts list.
Can you check if the port is still open after you apparently close it? You can use netstat -an, or an excellent tool ProcessExplorer. You can also check if the t_listener thread is terminating correctly (standard Task Manager or ProcessExplorer can help you).
Set the listener object to NULL so the resource is released which should also free the connection.
i have same problem, and the problem is in UDPClient.Receive(), she keep the socket in state of used even you call Close/shutdown/... `
try{ // receive loop}
catch{}
finally {
UDP_Listner.Close();
UDP_Listner = null;
}
EDIT :
t_listener = new Thread(UDPListener);//replace by :
t_listener = new Thread(new ThreadStart(UDPListener));
`
to safely close socket & thread ( http://msdn.microsoft.com/en-us/library/system.threading.threadstart(v=vs.110).aspx )
I have the same problem, I am the safest programmer, I always close everything nicely. yet I found that the .net class does not close the socket fast enough. because if I go slow it doesn't happen, but if I open and close(cleanup fully) and open it fast, I get the same error. especially if the user wants to run the same code again and open the port again.
Might be an old answer, but in your attempt to find a usable port, but which failed, i would dispose the listener instance you tested before the next iteration.
try
{
currPort = Int32.Parse(XSensAvailablePorts[currAttempt]);
listener = new UdpClient(currPort);
successfullAttempt = true;
}
catch (Exception e)
{
currAttempt++;
if(listener != null)
{
listener.Close();
}
}
I think Bind or reuse can solve this (even if socket is not closed yet it can be reused and no error is thrown)
Example code:
udpClient = new UdpClient();
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, p));
I'm writing a C# program that runs two IRC connections at once.
The connections are threaded, and each thread starts like so:
MainThread = new Thread(new ThreadStart(StartMainProcessor));
MainThread.IsBackground = false;
MainThread.Start();
private void StartMainProcessor() {
MainProcessor.Bot.Connect();
//while (true) { }
}
Bot.Connect() looks like this (somewhat abridged version):
public void Connect() {
try {
Client.Connect(IRCHelper.SERVER, IRCHelper.PORT);
}
catch (CouldNotConnectException e) {
Reconnect(true);
return;
}
try {
Client.Listen();
}
catch (Exception e) {
Reconnect(false);
return;
}
}
This works fine until the bot disconnects (which will always happen eventually, it's the nature of IRC).
When it disconnects, Reconnect() is called, which starts a timer. When that timer expires the bot is meant to then call Connect() again. The reason for the timer is that an IRC server will refuse an immediate reconnection sometimes.
However, once the Connect() method has ended, the Thread ends, and the program (console application) exits. (Client.Listen() is blocking)
I had previously overcome this problem by adding while (true) { } in StartMainProcessor()... But this eats up 100% CPU, and I'd really prefer a different solution.
Thank you for your help. :)
Sounds like you need a signaling construct. For example, you could use something like an AutoResetEvent to block the thread calling Reconnect, i.e. call Reconnect, start the timer and then block the thread. Then set the auto reset event in the timer expired event handler to allow the thread to continue (unblock) and call Connect.
I'm not a fan of spinning the processor - wastes huge amounts of CPU resources when you add infinite loops or sleeps in loops.
Why don't you just Thread.Sleep inside Bot.Reconnect? That would keep your thread alive and wake it up when ready to call Bot.Connect again.
You might want to try something like that
private bool canExitThread;
private void StartMainProcessor()
{
while (canExitThread)
{
//do the magic here
System.Threading.Thread.Sleep(1); //make sure you allow thread to do the job, otherwise you will get 100 cpu usage
//do the connecting, disconnecting, listening
}
}
Also can you check if Client is connected? if so then you should be checking that within the main loop and if it's disconnected - call the connect method.
Hope that gives you an idea how to do it.
Also have a look the the article below, which might explain things a little bit more.
http://msdn.microsoft.com/en-us/library/aa645740(v=vs.71).aspx
how about something like this
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace Server
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Starting server..");
foreach (var connection in new[] {new Connection(TimeSpan.FromSeconds(1)), new Connection(TimeSpan.FromSeconds(1))})
ThreadPool.QueueUserWorkItem(connection.Connect);
Console.WriteLine("Server running. Press Enter to quit.");
Console.ReadLine();
}
}
public class Connection //might be good to implement IDisposable and disconnect on Dipose()
{
private readonly TimeSpan _reConnectionPause;
public Connection(TimeSpan reConnectionPause)
{
_reConnectionPause = reConnectionPause;
}
//You probably need a Disconnect too
public void Connect(object state)
{
try
{
//for testing assume connection success Client.Connect(IRCHelper.SERVER, IRCHelper.PORT);
Debug.WriteLine("Open Connection");
}
catch (Exception)
{
//You might want a retry limit here
Connect(state);
}
try
{
//Client.Listen();
//Simulate sesison lifetime
Thread.Sleep(1000);
throw new Exception();
}
catch (Exception)
{
Debug.WriteLine("Session end");
Thread.Sleep(_reConnectionPause);
Connect(state);
}
}
}
}
I presume you have a Main method, so why don't we start there:
private static readonly MAX_NUM_BOTS = 2;
static void Main(string[] args)
{
List<Thread> ircBotThreads = new List<Thread>();
for(int numBots = 0; numBots < MAX_NUM_BOTS; numButs++)
{
Thread t = new Thread(()=>{StartMainProcessor();});
t.IsBackground = false;
t.Start();
ircBotThreads.Add(t);
}
// Block until all of your threads are done
foreach(Thread t in ircBotThreads)
{
t.Join();
}
Console.WriteLine("Goodbye!");
}
private static void StartMainProcessor()
{
MainProcessor.Bot.Connect();
}
Then you can do something like this:
// 30 second time out (or whatever you want)
private static readonly TimeSpan TIMEOUT = TimeSpan.FromSeconds(30.0);
// specify the maximum number of connection attempts
private static readonly int MAX_RECONNECTS = 10;
public void Connect()
{
bool shouldListen = false;
// This is your connect and re-connect loop
for(int i = 0; i < MAX_RECONNECTS; i++)
{
try
{
Client.Connect(IRCHelper.SERVER, IRCHelper.PORT);
shouldListen = true;
}
catch (CouldNotConnectException e)
{
// It's OK to sleep here, because you know exactly
// how long you need to wait before you try and
// reconnect
Thread.Sleep((long)TIMEOUT.TotalMilliseconds);
shouldListen = false;
}
}
while(shouldListen)
{
try
{
Client.Listen();
}
catch (Exception e)
{
// Handle the exception
}
}
}
This is a very rough draft, but the concept is that you keep trying to reconnect until you fail. Once you connect, then you listen (I presume you listen for something in IRC) and you process the data until you decide that you no longer need to be doing that work.
I have a simple class that handles the connection being made between a client and server.
To let more than one user communicate with the server at one time each new Client connection is made on a separate thread.
In this class I create two streams that act as the inbound and outbound streams for the client. I create the fields first and then initialise the object in a separate method, simply because the object is used in several other places.
I've come to the point where I want to refactor the code to make it more robust, my first port of call was memory management. I've come to love the using() statement but noticed that I can't really see a way to do implement it due to the way the code is structured.
This means I have a fairly annoying method that is just used for closing the underlying connections and nothing more.
Furthermore, I came to implement exception handling and was curious whether the notion of wrapping the entire code in a method with a try{} statement and then having sequential catch() blocks with the applicable exception types was the best idea.
I hope I explained myself correctly, I'll post a snippet for you to look at.
Thanks!
//Fields
TcpClient tcpClient;
//The thread that will send information to the client
private Thread thrSender;
private StreamReader srReceiver;
private StreamWriter swSender;
private string currentUser;
private string strResponse;
//The constructor of the class takes in a TCP connection
public Connection(TcpClient tcpCon)
{
tcpClient = tcpCon;
//The thread that accepts the client and waits messages
thrSender = new Thread(AcceptClient);
//The thread calls the AcceptClient method
thrSender.Start();
}
private void CloseConnection()
{
//Close the currently open objects
tcpClient.Close();
srReceiver.Close();
swSender.Close();
}
//Occurs when a new client is accepted
private void AcceptClient()
{
srReceiver = new StreamReader(tcpClient.GetStream());
swSender = new StreamWriter(tcpClient.GetStream());
//Read account information from the client
currentUser = srReceiver.ReadLine();
//Examine response from client
if (currentUser != "")
{
//Store the user name in the hash table
if (ChatServer.htUsers.Contains(currentUser) == true)
{
//0 means not connected - Writes error to Client and Server log
swSender.WriteLine("0|This username already exists.");
swSender.Flush();
CloseConnection();
return;
}
//More if/else if/else statements
//...
}
}
You can dispose of the two streams fairly easily within the AcceptClient method by making them local variables since they aren't referenced elsewhere something like this:
private void AcceptClient()
{
using (StreamReader srReceiver = new StreamReader(tcpClient.GetStream()))
{
using (StreamWriter swSender = new StreamWriter(tcpClient.GetStream()))
{
// ...
}
}
}
The tcpClient is more tricky because it is being created on one thread and cleaned up on another. Unless you can change that then perhaps the best option is going to be to implement the cleanup within a try/finally.
private void AcceptClient()
{
try
{
using (StreamReader srReceiver = new StreamReader(tcpClient.GetStream()))
{
using (StreamWriter swSender = new StreamWriter(tcpClient.GetStream()))
{
// ...
}
}
}
finally
{
tcpClient.Dispose();
}
}
The finally clause will get called whether or not the try clause throws an exception.
I'm building a (LAN) network application, so there is always the possibility that a connection will be disconnected, for various possible reasons. I am trying to think of a good design for handling this issue, such that it doesn't affect the rest of the application. I wrote a quick thing to try to do it, but I think it can be enhanced a lot. I appreciate your help and experience about the best way to handle this issue.
This is my first trial:
class ConnectionWrapper {
NetworkStream stream;
StreamReader reader;
Endpoint endPoint;
bool endOfStream;
int maxRetries = 5;
public void connect() {
// ... code to initialize a (TCP) socket to endPoint
this.stream = new NetworkStream(socket, true);
this.reader = new StreamReader(stream);
}
string readNextMsg() {
try {
string msg = reader.ReadLine();
if (msg == "EOF") endOfStream = true;
return msg;
}
catch (IOException e) {
Exception ex = e;
while (maxRetries-- > 0) {
try { connect(); ex = null; }
catch (Exception e2) { ex = e2; }
}
if (x != null) throw ex;
}
}
}
Not very elegant, and probably not the best that can be done. Could you please share your experience, and may be even suggest an existing library?
Thank you.
I honestly don't think you should let the connection wrapper contain logic to handle its own connection policy. I think this should be done from outside of this class, and especially not in the catch statement. Have some kind of ConnectionController object to deal with whether the connection should be retried once it fails.
I was going to edit my post, but this should be completely separate from my last one.
Your logic is all wrong in my opinion, you should have a thread within the ConnectionWrapper which spins on the StreamReader pulling off messages and placing them on a queue. This queue then notifies listeners of a change. The listeners then go and retrieve the data themselves and decide what needs to be done with them.
class ConnectionWrapper {
NetworkStream stream;
StreamReader reader;
Endpoint endPoint;
bool endOfStream;
int maxRetries = 5;
ArrayList arr;
public void connect() {
// ... code to initialize a (TCP) socket to endPoint
this.stream = new NetworkStream(socket, true);
this.reader = new StreamReader(stream);
}
private void initReceiverThread() {
String line;
while(stream.isConnected() && (line = reader.readLine()) != null) {
// notify observers of a change
arr.add(line);
}
}
}
This is pseudo-code I warn you, I've never done this in C#. A typical reader actually waits on a readLine statement, so the while loop won't go crazy. It's also best to put initReceiverThread code in a Thread, that way it won't block the rest of the application. By notifying the observers of a change they can then go and get the ArrayList by doing something like myConnectionWrapper.getMessages(); which will return an ArrayList, but also clearing out the ArrayList at the same time, like so:
public ArrayList getMessages() {
ArrayList temp = arr;
arr.clear();
return temp;
}
That way you get ALL of the messages and clear them off the queue.
I've written network clients before, and this is the general design of one. You'll have two threads constantly spinning, one to receiver messages, and one to send them.
The logic should be dealt with some kind of manager code to determine whether to continue, or reconnect or whatever you want to do.