I'm studying network and Windows forms with C# these days.
I'm trying to build an async-socket network system, everything's working well.
codes for Connect and Connect Callback are below.
private void ClientConnect()
{
CheckForIllegalCrossThreadCalls = false;
try
{
socket.BeginConnect(endPoint, new AsyncCallback(ConnectCallback), socket);
connectDone.WaitOne();
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private void ConnectCallback(IAsyncResult ar)
{
try
{
Socket client = (Socket)ar.AsyncState;
client.EndConnect(ar);
Send(socket, textBox3.Text, 0);
connectDone.Set();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
But in disconnecting socket, there's a problem.
I make a button to disconnect socket, and codes for button-clicked event are below.
private void btnDisconnect_Click(object sender, EventArgs e)
{
try
{
socket.Shutdown(SocketShutdown.Both);
Application.DoEvents();
socket.Disconnect(true); //-> problem occurs.
}
catch
{
MessageBox.Show("Disconnect Error!");
}
if (socket.Connected)
MessageBox.Show("Disconnect Error!");
else
textBox1.AppendText("Disconnected! (" + DateTime.Now.ToString("h:mm:ss tt") + ")\n");
}
When I disconnect the socket, 2 minutes of waiting time occurs.
after 2 minute(I checked this with time-stamp), It shows 'Disconnected' message.
And I can re-connect with this socket.
I think it is not just waiting like sleep, something's processed in background.
(Because mouse cursor's changed and program's blocked)
I'm so wondering why this delay(?) happens.
Please let me know.
Related
I know there are plenty of things about foreach freezing forms but I can't find a solution to my problem. I already have the server portion of this program working I am trying to make a client side that while connecting to the server this code will be preformed txtConn.AppendText("Attempting connection.");
This is the code that I have for the socket connection
private static Socket ConnectSocket(string server, int port, RichTextBox txtConn, BackgroundWorker backgroundWorker1)
{
Socket s = null;
IPHostEntry hostEntry = null;
// Get host related information.
hostEntry = Dns.GetHostEntry(server);
// Loop through the AddressList to obtain the supported AddressFamily. This is to avoid
// an exception that occurs when the host IP Address is not compatible with the address family
// (typical in the IPv6 case).
backgroundWorker1.RunWorkerAsync();
foreach (IPAddress address in hostEntry.AddressList)
{
IPEndPoint ipe = new IPEndPoint(address, port);
Socket tempSocket =
new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
Console.WriteLine(ipe);
try
{
attempt++;
txtConn.Select(txtConn.TextLength, 0);
txtConn.SelectionColor = Color.Aqua;
if (attempt == 1)
{
txtConn.AppendText("Attempting connection.");
}
else if (attempt > 1)
{
txtConn.AppendText("\r" + "Attempting connection.");
}
txtConn.SelectionColor = txtConn.ForeColor;
tempSocket.Connect(ipe);
}
catch (ArgumentNullException ane)
{
Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
txtConn.Select(txtConn.TextLength, 0);
txtConn.SelectionColor = Color.Red;
txtConn.AppendText("\r\n" + "Connection could not be established.");
txtConn.SelectionColor = txtConn.ForeColor;
}
catch (SocketException se)
{
Console.WriteLine("SocketException : {0}", se.ToString());
txtConn.Select(txtConn.TextLength, 0);
txtConn.SelectionColor = Color.Red;
txtConn.AppendText("\r\n" + "Connection could not be established.");
txtConn.SelectionColor = txtConn.ForeColor;
}
catch (Exception e)
{
Console.WriteLine("Unexpected exception : {0}", e.ToString());
txtConn.Select(txtConn.TextLength, 0);
txtConn.SelectionColor = Color.Red;
txtConn.AppendText("\r\n" + "Connection could not be established.");
txtConn.SelectionColor = txtConn.ForeColor;
}
if (tempSocket.Connected)
{
Console.WriteLine("Connected");
s = tempSocket;
break;
}
else
{
continue;
}
}
return s;
}
My program looks like this
When I run the program and connect with say the wrong Port, it checks all the possible ips on my computer and waits till after the foreach statement to display errors or anything. How can I make it actively display this?This is when it runs
You need to run your code in a different thread so that the UI can still update while it is executing.
The easiest way to do this is by adding the connection loop to a new task in the ThreadPool.
ThreadPool.QueueUserWorkItem(i => {
// Connection loop goes here.
});
If you need other options you can also use a Task, BackgroundWorker, etc.
I just answered a similar question here, but to expand on it for your particular case, it looks like you aren't actually using backgroundWorker1. The foreach should be done in a method referenced by the backgroundWorker1.DoWork event. You'll also need to create a method for the backgroundWorker1.ProgressChanged event. You can use ReportProgress to pass a string and then append that message to your textbox:
From your foreach loop in the Worker_DoWork method, you will report progress instead of updating the RichTextBox directly:
worker.ReportProgress(0, "Connection could not be established.");
And then in the Worker_ProgressChanged method, you will use something like this to update the RichTextBox:
txtConn.AppendText(e.UserState.ToString());
Use should use Async methods from Socket class or run this stuff in another thread. You can use BackgroundWorker to do that as well.
This is a follow on from this question
After some more Googling last night I managed to find a nice TCP tutorial I could follow that would allow me to look for connections on an Ip address and port number and display the data that is being sent.
However, I have an issue where my client connects once, I send a message and display it in the debug log but when I stop the application and run it again, Unity freezes. I'm at a loss as to why this happening. Could someone please take a look over this code to see where it might be happening and what I can do to fix it?
I also seem to boot out the connection as soon as I receive a message as well, why is that? The server can re-connect, but I want it to keep the connection once it has it.
public class TCP : MonoBehaviour
{
string ip_address = "127.0.0.1";
int port = 22;
Thread listen_thread;
TcpListener tcp_listener;
Thread clientThread;
TcpClient tcp_client;
bool isTrue = true;
// Use this for initialization
void Start ()
{
IPAddress ip_addy = IPAddress.Parse(ip_address);
tcp_listener = new TcpListener(ip_addy, port);
listen_thread = new Thread(new ThreadStart(ListenForClients));
listen_thread.Start();
Debug.Log("start thread");
}
private void ListenForClients()
{
this.tcp_listener.Start();
while(isTrue == true)
{
//blocks until a client has connected to the server
TcpClient client = this.tcp_listener.AcceptTcpClient();
//create a thread to handle communication
//with connected client
clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
Debug.Log("Got client " + client);
}
}
private void HandleClientComm(object client)
{
tcp_client = (TcpClient)client;
NetworkStream client_stream = tcp_client.GetStream();
byte[] message = new byte[4096];
int bytes_read;
while(isTrue == true)
{
bytes_read = 0;
try
{
//blocks until a client sends a message
bytes_read = client_stream.Read(message, 0, 4096);
//Debug.Log(message);
}
catch (Exception e)
{
//a socket error has occured
Debug.Log(e.Message);
break;
}
if(bytes_read == 0)
{
//client has disconnected
Debug.Log("Disconnected");
tcp_client.Close();
break;
}
ASCIIEncoding encoder = new ASCIIEncoding();
Debug.Log(encoder.GetString(message,0,bytes_read));
}
if(isTrue == false)
{
tcp_client.Close();
Debug.Log("closing tcp client");
}
}
void OnApplicationQuit()
{
try
{
tcp_client.Close();
isTrue = false;
}
catch(Exception e)
{
Debug.Log(e.Message);
}
}
}
Here is a screen shot of my debug log as well to show whats happening:
update
updated code that has fixed the kicking of clients. The freeze issue is still persistent when I stop the unity application and re-start it.
further update
So after a little further experimenting I have worked out that my project isn't actually freezing. When I start the server (Unity) app the first time everything works fine. But when I close it and try to re run the server, it freezes, until I connect to it with a client. At which point the server works as normal.
So I think I'm not closing the open socket when I close down the server. How can I do that?
You must close the TCP socket that is listening. If you start the application for the first time, the TCP socket will be open. When you stop the application, the TCP socket is still opened and runs in the background.
void OnApplicationQuit()
{
try
{
tcp_client.Close();
isTrue = false;
}
catch(Exception e)
{
Debug.Log(e.Message);
}
// You must close the tcp listener
try
{
tcp_listener.Stop();
isTrue = false;
}
catch(Exception e)
{
Debug.Log(e.Message);
}
}
I have a server client implementation using WCF where the clients sends a Connect message to the server when it starts.
This is the code I'm using in my client application (WCF service is self hosted in this case):
public void InitializeCommunicationChannel()
{
this._proxy = new DistributionServiceClient(this._context, "NetTcpBinding_IDistributionService");
Log.Write(Level.Debug, "Initialized proxy..");
//set credentials
this._proxy.ClientCredentials.Windows.ClientCredential.Domain = PasswordManager.ServerAdminDomain;
this._proxy.ClientCredentials.Windows.ClientCredential.UserName = PasswordManager.ServerAdminUsername;
this._proxy.ClientCredentials.Windows.ClientCredential.Password = PasswordManager.ServerAdminPassword;
this._proxy.InnerChannel.Faulted += new EventHandler(this.InnerChannel_Faulted);
this._proxy.InnerChannel.Closing += new EventHandler(this.InnerChannel_Closing);
//send a connect message to the server
try
{
Log.Write(Level.Debug, "Sending connect message..");
this.StationId = this._proxy.ClientConnected(ClientConfiguration.HostName, this.Version, ClientConfiguration.CurrentIpAddress);
Log.Write(Level.Debug, "Connect message sent..");
Log.Write(Level.Info, "Connected to server.");
this.ConnectionState = "Connected";
}
catch (ConfigurationErrorsException cEx)
{
Log.Write(Level.Error, cEx.Message);
Log.Write(Level.Debug, cEx.ToString());
}
catch (FaultException fEx)
{
//probably server didn't recognize configured ip or hostname
Log.Write(Level.Error, fEx.Message);
Log.Write(Level.Debug, fEx.ToString());
}
catch (CommunicationException cEx)
{
Log.Write(Level.Debug, cEx.Message);
Log.Write(Level.Debug, cEx.ToString());
}
catch (System.Security.Authentication.InvalidCredentialException iEx)
{
Log.Write(Level.Error, iEx.Message);
Log.Write(Level.Debug, iEx.ToString());
}
catch (Exception ex)
{
Log.Write(Level.Error, ex.Message);
Log.Write(Level.Debug, ex.ToString());
}
void InnerChannel_Closing(object sender, EventArgs e)
{
Log.Write(Level.Debug, "Communication channel is closing down..");
this.ConnectionState = "Attempting connection..";
}
void InnerChannel_Faulted(object sender, EventArgs e)
{
this.ConnectionState = "Not connected";
Log.Write(Level.Debug, "Communication channel faulted..");
//something went wrong
this._proxy.Abort();
this._proxy.InnerChannel.Faulted -= this.InnerChannel_Faulted;
this._proxy.InnerChannel.Closing -= this.InnerChannel_Closing;
//give the server a chance to get back online; retry after 10s
Thread.Sleep(10000);
//re-initialize the communication channel
this.InitializeCommunicationChannel();
}
The problem that I'm having is that when the server address is not correctly configured in the client's config file, the channel faults when I try to send the Connect message, but no exception is being caught.
Is this because the connection is occurring on a different thread therefore it never ends up in my catch code? How do I catch endpoint configuration exceptions in code? The InnerChannel_Faulted's EventArgs member doesn't contain any useful information.
Thanks a lot.
When I want to open a new Thread for every Incoming Request. Is this good way to do it? Will there be a new Thread with every accepted Request? The BeginReceive Method called in the end of this piece of code Works asynchronous aswell.
public void Listen(IPEndPoint EndPoint)
{
try
{
ListeningSocket.Bind(EndPoint);
ListeningSocket.Listen(BACKLOG);
BeginAccept();
}
catch (Exception e)
{
Console.WriteLine(e.Message + "\nfrom Source: " + e.Source + "\nand Stack Trace: " + e.StackTrace);
}
}
public void BeginAccept()
{
try
{
ListeningSocket.BeginAccept(new AsyncCallback(Accept_Callback), new ServerSocket());
}
catch (SocketException e)
{
Console.WriteLine("Listening Socket Error:" + e.ErrorCode);
}
catch (ObjectDisposedException e)
{
Console.WriteLine("The Listening Socket has been closed");
}
}
private void Accept_Callback(IAsyncResult asyncResult)
{
BeginAccept();
try
{
if (asyncResult.AsyncState != null)
{
ServerSocket serverSocket = asyncResult.AsyncState as ServerSocket;
if ((serverSocket.CommunicationSocket = ListeningSocket.EndAccept(asyncResult)) != null)
{
BeginReceive(serverSocket);
}
}
}
catch (SocketException e)
{
Console.WriteLine("Listening Socket Error:" + e.ErrorCode);
}
catch (ObjectDisposedException e)
{
Console.WriteLine("The Listening Socket has been closed");
}
}
This approach uses threads from a ThreadPool which is a good thing. While waiting for a new client to be accepted or for data to arrive no threads are used, so your code will not span 1000 threads when you have 1000 clients connected.
Just when data arrives on one socket, one free thread will be taken from the tread pool and will process your callback. When your method finishes, the thread will be returned to the pool to be available for the next data arrival or client connection.
I have the following code. An error occurs and the code simply breaks at _clientStreamWriter.Flush(); at the SendData method.
No error is given, no exception is thrown... the program just stops. Any help? Thanks!
public class clsTCPClient
{
TcpClient TCPClient = new TcpClient();
StreamWriter _clientStreamWriter;
public bool Connect(string Dest, int Port)
{
try
{
if (!TCPClient.Connected)
{
TCPClient.Connect(Dest, Port);
_clientStreamWriter = new StreamWriter(TCPClient.GetStream());
}
}
catch(Exception e)
{
utilities.WriteLog(utilities.LogDir + "\\AEOS.log", e.ToString());
return false;
}
return true;
}
public void SendData(string Data)
{
try
{
//send message to server
_clientStreamWriter.WriteLine(Data);
_clientStreamWriter.Flush();
}
catch(Exception e)
{
utilities.WriteLog(utilities.LogDir + "\\AEOS.log", e.ToString());
}
}
}
TCP is a reliable connection. You need to read all data on the server side and properly finish reading for your code to move further. You probably will get the exception after timeout.
Edit:
I just tested it and actually Flush() shouldn't block even if you don't accept socket or read any data on server side. So it must be some other problem.