I'm working on a desktop application that involves a TcpListener.
I'm attempting to create the TcpListener and handle clients in a background thread...
private TcpListener _listener;
public MainWindow()
{
InitializeComponent();
DataContext = _vm;
Thread smtpThread = new Thread(new ThreadStart(StartSmtpLocal));
smtpThread.Start();
}
void StartSmtpLocal()
{
_listener = new TcpListener(IPAddress.Any, 1025);
_listener.Start();
while (true)
{
Console.WriteLine("Waiting for connection...");
TcpClient client = _listener.AcceptTcpClient();
Console.WriteLine($"Client status: {client.Connected}"); // This is 'Client status: True'
SMTPServer handler = new SMTPServer();
handlers.Add(handler);
handler.Initialize(client, SmtpMessageComplete);
Thread thread = new Thread(new ThreadStart(handler.Run));
thread.Start();
}
}
My SMTPServer.Initialize method is simply storing a reference to the TcpClient.
private TcpClient _client;
private Action<MimeMessage> _finishAction;
private MimeMessage _messageRead;
public void Initialize(TcpClient client, Action<MimeMessage> finishAction)
{
_client = client;
_finishAction = finishAction;
}
And Run would process messages from the client. However immediately upon entering Run in the new thread, the client is disconnected.
public void Run()
{
Write("220 localhost -- Fake proxy server");
Console.WriteLine($"Client status {_client.Connected}"); // This is 'Client status False'
...
}
Any ideas on what is causing the client to disconnect here?
Thanks!
Related
I am trying to write a TCP listener that can connect to multiple clients and send and receive data.
Some of my code -
Calling server -
private void Form1_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'cresijCamDataSet1.CentralControl' table. You can move, or remove it, as needed.
this.centralControlTableAdapter1.Fill(this.cresijCamDataSet1.CentralControl);
s = new Server();
Thread th = new Thread(s.Run);
th.Start();
}
Run Method -
public async void Run()
{
tcp = new TcpListener(IPAddress.Any, 1200);
tcp.Start();
while (true)
{
try
{
TcpClient client = await tcp.AcceptTcpClientAsync();
Thread th = new Thread(()=>{
Process(client);
}) ;
}
catch (Exception ex)
{
string m = ex.Message;
}
}
}
private async Task Process(TcpClient tcpClient)
{
bool hasItem = clients.Contains(tcpClient);
if(hasItem == false)
{
clients.Add(tcpClient);
}
IPEndPoint iPEndPoint =(IPEndPoint) tcpClient.Client.RemoteEndPoint;
string ip = ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address.ToString();
NetworkStream stream = tcpClient.GetStream();
byte[] receivedBytes = new byte[tcpClient.ReceiveBufferSize];
stream.Read(receivedBytes, 0, receivedBytes.Length);
f.UpdateData(receivedBytes, ip);
}
Sender Method to send data -
public void Sender(byte[] data, TcpClient client)
{
NetworkStream stream = client.GetStream();
stream.Write(data, 0, data.Length);
}
As you can see I have called Run() method in formLoad. But this all is not working as I dont have much knowledge of threads.
This method is not continuous. The server is not listening to clients always. Can someone help me with this. I need asynchronuous tcp listener that can listen to incoming clients and that too in windows form. Console Server I have.
I'm trying to create a windows service that needs to run in the background and listen for incoming traffic (a normal and regular TCP listener)
my code is:
private TcpListener server;
public void startServer()
{
// EventLog.WriteEntry(source, "connected on: " + ipAddress.ToString() + " port: " + Service1.Port.ToString());
server = new TcpListener(IPAddress.Parse("127.0.0.1"), Service1.Port);
server.Start();
while (true)
{
var client = server.AcceptTcpClient();
new Thread(work).Start(client);
}
public void work(object client)
{
string msg = null;
var clientLocal = (TcpClient)client;
using (NetworkStream ns = clientLocal.GetStream())
using (StreamReader sr = new StreamReader(ns))
{
byte[] msgFullArray = new UTF8Encoding(true).GetBytes(msg);
fs.Write(msgFullArray, 0, msg.Length);
}
now if you don't look at the work method at all as whenever i start my service it freezes whenever i try to start it at my :
var client = server.AcceptTcpClient();
meaning my service never gets to use the Thread or my Work method..
i can see from previous logging that it enters my while loop and then just times out the service
In your OnStart Method you have to instantiate a server class.
protected override void OnStart(string[] args)
{
// Create the Server Object ans Start it.
server = new TCPServer();
server.StartServer();
}
that is responsible to handle the connections to the server by creating a new Thread (so that it is a non-blocking process)
public void StartServer()
{
if (m_server!=null)
{
// Create a ArrayList for storing SocketListeners before
// starting the server.
m_socketListenersList = new ArrayList();
// Start the Server and start the thread to listen client
// requests.
m_server.Start();
m_serverThread = new Thread(new ThreadStart(ServerThreadStart));
m_serverThread.Start();
// Create a low priority thread that checks and deletes client
// SocktConnection objcts that are marked for deletion.
m_purgingThread = new Thread(new ThreadStart(PurgingThreadStart));
m_purgingThread.Priority=ThreadPriority.Lowest;
m_purgingThread.Start();
}
}
for each socket that it will be listening by a TCPListener.
private void ServerThreadStart()
{
// Client Socket variable;
Socket clientSocket = null;
TCPSocketListener socketListener = null;
while(!m_stopServer)
{
try
{
// Wait for any client requests and if there is any
// request from any client accept it (Wait indefinitely).
clientSocket = m_server.AcceptSocket();
// Create a SocketListener object for the client.
socketListener = new TCPSocketListener(clientSocket);
// Add the socket listener to an array list in a thread
// safe fashon.
//Monitor.Enter(m_socketListenersList);
lock(m_socketListenersList)
{
m_socketListenersList.Add(socketListener);
}
//Monitor.Exit(m_socketListenersList);
// Start a communicating with the client in a different
// thread.
socketListener.StartSocketListener();
}
catch (SocketException se)
{
m_stopServer = true;
}
}
}
Here it is the full project article.
Client
class Client
{
public TcpClient client;
public StreamWriter server;
public ServerPlayer serverPlayer;
public Player player;
public void Connect(Player p)
{
player = p;
serverPlayer = new ServerPlayer();
client = new TcpClient(AddressFamily.InterNetwork);
client.Connect("Don't wory my IPV4 Is Here", 8888);
NetworkStream stream = client.GetStream();
server = new StreamWriter(stream);
Timer t = new Timer(Send, null, 0, 10);
}
public void Send(Object o)
{
server.WriteLine("Hello I am bob");
server.Flush();
}
}
Server
class TcpServerConnection
{
private static TcpListener tcpListener;
static void Main(string[] args)
{
tcpListener = new TcpListener(IPAddress.Any, 8888);
tcpListener.Start();
Console.WriteLine("Server started.");
while (true)
{
//blocks until a client has connected to the server
TcpClient client = tcpListener.AcceptTcpClient();
//create a thread to handle communication
//with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
}
private static void HandleClientComm(object client)
{
while (true)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
StreamReader server = new StreamReader(clientStream);
Console.WriteLine(server.ReadLine());
}
}
}
Problem
Track of events:
Started!
Hello I am bob
Hello I am bob
(Many Hello I am bobs later)
Hello I am bob
(Hello I am bobs just stopped)
(About 30 seconds)
Don't know if it because the client stops sending or server stops receiving or both!? But once this is ran about 30 seconds into this the server stops getting the send information. No error is thrown simply it just doesn't send.
Found out it was my internet. After my google-fu. I set my port for my server to be TCP open. Found out my router was getting suspicious after a spam of messages going into a random port. IP:IPV4 PORT:8888 SETTINGS:OPEN
Ok in your ServerConnection object the first while loop is fine. but the one in your handler is going to cause some problems try this:
private static void HandleClientComm(object client)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
using(var stream = new StreamReader(clientStream))
{
while (stream.Peek() >= 0)
{
Console.WriteLine(server.ReadLine());
}
}
}
Since you are creating one and only one connection to the Server, and then sending messages constantly in the Client, accordingly when handling the client messages in the Server program, you should accept a TcpClient and then read messages in a loop, instead of accepting a Tcplient and reading a message all in a loop.
private static void HandleClientComm(object client)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
StreamReader server = new StreamReader(clientStream);
while (true)
{
Console.WriteLine(server.ReadLine());
}
}
I have the following code which I want to implement as my server. As I understand it is async. and should allow connections from multiple clients...
public void Start()
{
TcpListener listener = new TcpListener(IPAddress.Any, 10250);
listener.Start();
Console.WriteLine("Listening...");
while (true)
{
IAsyncResult res = listener.BeginAcceptTcpClient(HandleAsyncConnection, listener);
connectionWaitHandle.WaitOne();
}
}
private void HandleAsyncConnection(IAsyncResult res)
{
TcpListener listener = (TcpListener)res.AsyncState;
TcpClient client = listener.EndAcceptTcpClient(res);
connectionWaitHandle.Set();
StringBuilder sb = new StringBuilder();
var data = new byte[client.ReceiveBufferSize];
using (NetworkStream ns = client.GetStream())
{
// Test reply
Byte[] replyData = System.Text.Encoding.ASCII.GetBytes(DateTime.Now.ToString());
ns.Write(replyData, 0, replyData.Length);
ns.Flush();
ns.Close();
}
client.Close();
}
I have a test app which simply fires requests to my server. As you can see in the code the server just replies with its date/time. The test app sends say 20 requests which are simply test strings. For each of these requests it opens a socket, sends the data to my server and then closes the socket again.
This works fine with one test app running. However, if I open two test apps the second one cannot connect to the server. I thought because I am handling the request async. and because my test app opens then closes the socket before each call I could handle requests from multiple clients?
Edit
If using >=.Net4.5, it's better to use the new network methods that then permit the adoption of async and await. As such, it might be better to follow the example I provided in this post as a starting point.
Original Post
The following code demonstrates how to accept multiple clients asynchronously without spinning off a new thread per connection.
private TcpListener listener;
public void Start()
{
listener = new TcpListener(IPAddress.Any, 10250);
listener.Start();
Console.WriteLine("Listening...");
StartAccept();
}
private void StartAccept()
{
listener.BeginAcceptTcpClient(HandleAsyncConnection, listener);
}
private void HandleAsyncConnection(IAsyncResult res)
{
StartAccept(); //listen for new connections again
TcpClient client = listener.EndAcceptTcpClient(res);
//proceed
}
You can use this pattern for most async operations.
The way you did it, there is no benefit compared to using AcceptTcpClient. Simply loop and create a new thread for each accepted connection:
public void Start()
{
TcpListener listener = new TcpListener(IPAddress.Any, 10250);
listener.Start();
Console.WriteLine("Listening...");
while (canRun)
{
var client = listener.AcceptTcpClient();
new Thread(ClientThread).Start(client);
}
}
private void ClientThread(IAsyncResult res)
{
TcpClient client = (TcpClient)res.AsyncState;
StringBuilder sb = new StringBuilder();
var data = new byte[client.ReceiveBufferSize];
using (NetworkStream ns = client.GetStream())
{
// Test reply
Byte[] replyData = System.Text.Encoding.ASCII.GetBytes(DateTime.Now.ToString());
ns.Write(replyData, 0, replyData.Length);
ns.Flush();
ns.Close();
}
client.Close();
}
A golden rule when using asynchronous methods is to NOT block the operation. Blocking would defeat the purpose of using async ops.
public void Start()
{
TcpListener listener = new TcpListener(IPAddress.Any, 10250);
listener.Start();
Console.WriteLine("Listening...");
listener.BeginAcceptTcpClient(OnAccept, listener);
}
private void OnAccept(IAsyncResult res)
{
TcpListener listener = (TcpListener)res.AsyncState;
TcpClient client = listener.EndAcceptTcpClient(res);
StringBuilder sb = new StringBuilder();
var data = new byte[client.ReceiveBufferSize];
using (NetworkStream ns = client.GetStream())
{
// Test reply
Byte[] replyData = System.Text.Encoding.ASCII.GetBytes(DateTime.Now.ToString());
ns.Write(replyData, 0, replyData.Length);
ns.Flush();
ns.Close();
}
client.Close();
}
is there a way to limit the number of clients a tcpListener can accept?
Count them and dont accept() if you have too many?
You can count it in your event handlerclass Server()
{
private AutoResetEvent connectionWaitHandle = new AutoResetEvent(false);
public void Start()
{
TcpListener listener = new TcpListener(IPAddress.Any, 5555);
listener.Start();
while(true)
{
IAsyncResult result = tcpListener.BeginAcceptTcpClient(HandleAsyncConnection, tcpListener);
connectionWaitHandle.WaitOne(); //Wait until a client has begun handling an event
}
}
private void HandleAsyncConnection(IAsyncResult result)
{
TcpListener listener = (TcpListener)result.AsyncState;
TcpClient client = listener.EndAcceptTcpClient(result);
connectionWaitHandle.Set(); //Inform the main thread this connection is now handled
//... Use your TcpClient here
client.Close();
}
}