Lets say you having the following code.
this._tcpListener.Start();
while (true)
{
//blocks until a client has connected to the server
TcpClient client = this._tcpListener.AcceptTcpClient();
//create a thread to handle communication
//with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientCommunication));
clientThread.Start(client);
}
private void HandleClientCommunication(object client)
{
using (TcpClient tcpClient = (TcpClient) client)
{
//Do my work
}
}
The problem with such an implementation is that whatever port I have used in the initial connection is then used in the client communication and therefor (despite the fact that the tcpListener is still listening it will be unable to accept other connections till the port is freed).
So is there someway to tell the tcpClient to change the port it is working on or is the only way to implement such functionality by sending back the client a new port number and telling it to reconnect?
IE:
TcpListener1.AcceptTcpClient(); //Wait
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientCommunication));
clientThread.Start(client);
private void HandleClientCommunication(object client)
{
using (TcpClient tcpClient = (TcpClient) client)
{
//Generate random port number send back to client and create another thread with a new tcpListener and wait again?
}
}
Looking at the code it appears that
the localendpoint for the client and
the remoteendpoint for the server
appears to change to a different port
yet the inverse in each case stays the
same.
IE:
Started server tcpListener on 121
ClientLocalEndPoint: {127.0.0.1:1380}
ClientRemoteEndPoint: {127.0.0.1:121}
ServerLocalEndPoint: {127.0.0.1:121}
ServerRemoteEndPoint: {127.0.0.1:1380}
You are incorrect about the problem here; Spawning a new thread to handle the TcpClient and then looping back to TcpListener.AcceptTcpClient() does not require you to change ports; A single server can get multiple connections in to the same socket.
Otherwise, how would web servers handle multiple users at once?
Something else is going wrong with your code somewhere. Your "thread-per-connection" code is not ideal (a thread per connection is much more than is needed), but it is a quick-and-dirty way that works just fine.
How are you constructing the Listener? What are you doing with the client? And what exactly is happening to subsequent connections?
I agree with others that you might want to look at asynchronous methods instead of using separate threads for each connection, or at least BackgroundWorker... As for what is happening, did you try debugging making sure that you had one thread stuck on the AcceptTcpClient call? You could try specifying a high backlog in your Start() call. Could it be something with scope and maybe garbage collection of your thread because you don't maintain a reference for it? If you put a Thread.Sleep(10000) at the end of your loop, can you connect after 10 seconds? If you try using command line telnet to connect to the port (i.e. "telnet localhost 9999") does the screen blank showing that it connected?
You could try something like adding a hashtable to store your threads and remove them on exit which adds the benefit of having a list of them and being able to close the connections and kill them...
Dictionary<TcpClient, Thread> _threads = new Dictionary<TcpClient, Thread>();
object _lockObject = new object();
void AddThread(TcpClient client, Thread thread)
{
lock (_lockObject)
{
_threads.Add(client, thread);
}
}
void RemoveThread(TcpClient client)
{
lock (_lockObject)
{
_threads.Remove(client);
}
}
void YourMainMethod()
{
this._tcpListener.Start();
while (true)
{
//blocks until a client has connected to the server
TcpClient client = this._tcpListener.AcceptTcpClient();
//create a thread to handle communication
//with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientCommunication));
AddThread(client, clientThread);
clientThread.Start(client);
}
}
private void HandleClientCommunication(object client)
{
try
{
using (TcpClient tcpClient = (TcpClient) client)
{
//Do my work
}
} catch (Exception)
{
// so program doesn't crash
}
finally
{
RemoveThread((TcpClient)client);
}
}
Related
I wrote some code using TcpListener and async/await which will wait for 3 clients to connect to the server, add them to a list, then do something with the clients:
private async void button1_Click(object sender, EventArgs e)
{
var listener = new TcpListener(IPAddress.Any, 6015);
listener.Start();
var clients = await Task.Run(() => GetTcpClients(listener));
// Do something with clients
listener.Stop();
}
private static async Task<List<TcpClient>> GetTcpClients(TcpListener listener)
{
var clients = new List<TcpClient>();
var clientsMaxReached = false;
while (!clientsMaxReached)
{
var client = await listener.AcceptTcpClientAsync();
clients.Add(client);
if (clients.Count == 3)
clientsMaxReached = true;
}
return clients;
}
What I am concerned about is whether it's okay to use a List for the clients instead of a thread-safe collection, since the await may resume on a different thread. Also, just wondering if my TcpListener usage is thread safe too.
I don't see a problem since no two threads will ever access the list or TcpListener at the same time, but just thought I'd check.
Both the accesses to list and listener are thread safe.
The clients list is not accessed and accessible by anybody else until the list is completely built. Any code after await will not execute until the awaited task/method is completed.
For the listener it's pretty much the same but in opposite direction. The instance is passed to getTcpClients() method but any other access is blocked until this method stops working with the instance.
I'm writng a c# tcp socket server which will receive data from c++ socket application. Now everything works good except the loop break logic inside my c# receiving thread. I'm showing a code snippet below to explain better.
//creating socket object
private Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//accepting connections
TcpListener tcpListener = new TcpListener(ipAdd, iPort);
tcpListener.Start();
this.socket = tcpListener.AcceptSocket();
tcpListener.Stop();
//code for
//public byte[] ReceiveMessage(ref int intError)
while (this.socket.Available > 0)
{
try
{
intBytesReceived = this.socket.Receive(byteReceivedBuffer, byteReceivedBuffer.Length, SocketFlags.None);
Thread.Sleep(100);
}
catch (SocketException ex)
{
string str = ex.Message;
intError = -1;
}
}
Below is the thread function to receive data continuously
//Thread to continuous poll data from client
//Now this has been done as I need to receive multiple messages from client after server ack received at client side.
//Thread quit logic based on manual stop button press
//I want to have one more logic by which thread will exit if the connection closed by client socket. i.e. a call of 'CloseSocket()' function from c++ application.
if (TCPServerListener.serverStatus == TCPServerListener.ServerStatus.Stopped)
{
tcpCommunication.Disconnect();
break;
}
while(true)
{
int sockError = 0;
byte[] byteData = tcpCommunication.ReceiveMessage(ref sockError);
if (byteData.Length > 0)
{
ParseBuffer(byteData, ref tcpCommunication);
}
}
For better picture I'm wrting below my communication protocol.
Client initiate a connection. Send a data set
Server receives, process, send ack
Client is in halt mode until it receive the ack from server, but didn't close the socket
This time, server will not receive any message but the receiving thread should active as I'm creating a single thread for each client.
Once the client receives the ack it will continue to send next data
Server receiving thread will get data now and process accordingly
Once client closes down its socket, server receiver thread should close also
I'm able to getting my work done but the server receiver thread is not getting closed. That's my problem. Any suggestions would be a off great help.
It has been my experience that when you use a TCP server/client socket relationship, the TCP server socket side will be in a thread that is controlled by a flag to continue listening until told to stop (Your comments mention a stop button).
The client side runs until all data is done, or the same flag controlling the server side is tripped.
When a client connects, I would store the AcceptSocket into a list. When I did this, I had a custom class that the takes the AcceptSocket and the custom class had counters for like how many messages, or bytes was sent/received to/from this client.
// This should be a threaded method if you're using a button to stop
private void StartTcpListener()
{
List<ClientClass> clientClassList = new List<ClientClass>();
TcpListener tcpListener = new TcpListener(ipAdd, iPort);
tcpListener.Start();
while (keepListening)
{
Socket socket = tcpListener.AcceptSocket();
// Create a client object and store it in a list
ClientClass clientClass = new ClientClass(socket);
clientClassList.Add(clientClass);
// This method would start a thread to read data from the accept socket while it was connected.
clientClass.Start();
}
foreach (ClientClass client in clientClassList)
{
// This method would stop the thread that reads data from the accept socket and close the accept socket
client.Stop();
}
tcpListener.Stop();
}
For the client side, when reading from the client accept socket this would be thread controlled and either the thread is aborted or the client closes its end causing the read to return a -1 for number of bytes read.
// Threaded method
private void Receive()
{
// Don't know how much of a buffer you need
byte[] dataIn = byte[1000];
while (acceptSocket.Connected)
{
// Exception handling so you either end the thread or keep processing data
try
{
int bytesRead = acceptSocket.Read(dataIn);
if (bytesRead != -1)
{
// Process your data
}
else
{
// -1 Bytes read should indicate the client shutdown on their end
break;
}
}
catch(SocketException se)
{
// You could exit this loop depending on the SocketException
}
catch(ThreadAbortException tae)
{
// Exit the loop
}
catch (Exception e)
{
// Handle exception, but keep reading for data
}
}
// You have to check in case the socket was disposed or was never successfully created
if (acceptSocket != null)
{
acceptSocket.Close();
}
}
// This is the stop method if you press your stop button
private void Stop()
{
// Aborts your read thread and the socket should be closed in the read thread. The read thread should have a ThreadState.Stopped if the while loop was gracefully ended and the socket has already been closed
if (readThread != null && readThread.ThreadState != ThreadState.Stopped)
{
readThread.Abort();
}
}
I think this is the basics of what I've done before. I'm sure there are "cleaner" ways of doing this now. This was years ago when I use to implement TCP client/server socket objects.
Hope this helps...
I'm having problems listening for connections within a TCPListener, basically I am running this on a different thread as so:
listenThread = new Thread(new ThreadStart(Listen));
void Listen(...)
{
while (true)
{
Socket socket = Listener.AcceptSocket();
Connection connection = new Connection(socket);
connection.onInit();
Thread.Sleep(100);
Listen();
}
}
I have no idea what to do next to solve this "Stackoverflow" Exception, I need to listen to connections on a different thread like the way I've coded it, any suggestions to fix it?
Listen() is calling itself which will eventually result in a stack overflow.
Simply remove the call to Listen() at end of the while loop.
Why I am getting program hang on the tcpClient = this.ss.AcceptTcpClient?
public virtual void Run()
{
if (this.tcpListener == null)
return;
TcpClient tcpClient = (TcpClient)null;
while (!this.m_Stop)
{
try
{
tcpClient = this.tcpListener.AcceptTcpClient();
ThreadPool.QueueUserWorkItem(new WaitCallback(this.handler.Handle), (object)tcpClient);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
Here ss is the TcpListener.
I googled for TcpListener.AcceptTcpClient Method. This is what I found.
AcceptTcpClient is a blocking method that returns a TcpClient that you
can use to send and receive data. Use the Pending method to determine
if connection requests are available in the incoming connection queue
if you want to avoid blocking.
It seems that the method waits till there is a connection request available. So either use the Pending method call or do this on a background thread (not the UI thread).
I am running a C# server from the main application and I would like to pass the message received from the server thread to the main thread. The server should be running on the background for new connections. Every time there is a new connection the server should pass the message received to the main app. How can let the main app know when the message is received? and how can pass the message from the server thread to the main when there is a new connection?
Main application
public partial class MainWindow : Window
{
TCPServer Server = new TCPServer(); //start running the server
//get the message (Server.message) when a client sent it to the server
//TODO process the message
}
TCP server
class TCPServer
{
private TcpListener tcpListener;
private Thread listenThread;
private String message;
public TCPServer()
{
this.tcpListener = new TcpListener(IPAddress.Any, 3200);
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
//starts the tcp listener and accept connections
private void ListenForClients()
{
this.tcpListener.Start();
while (true)
{
//blocks until a client has connected to the server
System.Diagnostics.Debug.WriteLine("Listening...");
TcpClient client = this.tcpListener.AcceptTcpClient();
System.Diagnostics.Debug.WriteLine("Client connected");
//create a thread to handle communication
//with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
}
//Read the data from the client
private void HandleClientComm(object client)
{
TcpClient tcpClient = (TcpClient)client; //start the client
NetworkStream clientStream = tcpClient.GetStream(); //get the stream of data for network access
byte[] message = new byte[4096];
int bytesRead;
while (true)
{
bytesRead = 0;
try
{
//blocks until a client sends a message
bytesRead = clientStream.Read(message, 0, 4096);
}
catch
{
//a socket error has occured
break;
}
if (bytesRead == 0) //if we receive 0 bytes
{
//the client has disconnected from the server
break;
}
//message has successfully been received
ASCIIEncoding encoder = new ASCIIEncoding();
message = encoder.GetString(message, 0, bytesRead);
//Reply
byte[] buffer = encoder.GetBytes("ACK");
clientStream.Write(buffer, 0, buffer.Length);
System.Diagnostics.Debug.WriteLine("ACK");
clientStream.Flush();
}
tcpClient.Close();
System.Diagnostics.Debug.WriteLine("Client disconnected");
}
This is already well supported by TcpListener, use the BeginAcceptTcpClient() method instead. When you call it from the main thread of a WPF or Winforms app then the callback will run on the same main thread automatically. The same applies to its BeginReceive() method. Internally it uses the dispatcher loop to get the callback method activated, pretty similar to the way a class like BackgroundWorker and the C# v5 async/await keywords work.
This saves you from the hassle of starting end terminating your own thread and ensuring you marshal back properly. And significantly cutting down on the resource usage of your program. Highly recommended.
A Queue is the answer. Specifically in this case a Concurrent Queue.
Your socket thread puts messages into the queue. Your worker thread(s) poll the queue and pulls work items out.
For socket based applications, this pattern is very, very common.
Alternatively, you can QueueUserWorkItem against the system thread pool, and let it manage the work load.
Note: You're in multi-threaded land now. You'll need to read about synchronization and other issues that are going to arise. Failure to do this means your app will have very weird bugs.