I'm trying to create my own chat app as a school project.
I have almost everything ready, connected with DB, backend. The only thing that is weighing me down right now is adding a TCP Server to the project for communication between Clients.
It's not supposed to be anything big, so just short code, plus I don't have that much experience with TCP in C#.
The code works, but the problem is that the Application/Window doesn't appear.
I suspected that the problem might be in the MainWindow() constructor due to the infinite loop (this was also confirmed here on SO). Unfortunately I don't know how to fix it anymore. I first had the server as a separate class, but I ran into this problem. So I tried implementing it directly in the class, or breaking the connection after shutting down the application.
public partial class MainWindow: Window {
private TcpListener myServer;
private bool isRunning;
public MainWindow() {
InitializeComponent();
myServer = new TcpListener(IPAddress.Any, 65525);
myServer.Start();
isRunning = true;
LoopServer();
}
private void LoopServer() {
while (isRunning) {
TcpClient client = myServer.AcceptTcpClient();
Thread thread = new Thread(new ParameterizedThreadStart(LoopClient));
thread.Start(client);
}
}
private void LoopClient(object obj) {
TcpClient client = (TcpClient) obj;
StreamReader reader = new StreamReader(client.GetStream(), Encoding.UTF8);
StreamWriter writer = new StreamWriter(client.GetStream(), Encoding.UTF8);
MessageBox.Show("Connected bro!");
writer.Flush();
bool clientRunning = true;
while (clientRunning) {
string data = reader.ReadLine();
MessageBox.Show(data);
writer.Flush();
}
}
}
An infinite loop is okay for a server to be running in. Generally, you can start up the server (1st application). The clients (different application) can connect to it and then process messages and broadcast them to all the clients appropriately.
Super simple example: Build Chat in C#
Alternatively you can try an event based approach to the TCP listener.
Related
I am working on a windows service that should collect all incoming TCP/IP streams with this class. It gets started from the services OnStart() void.
However I have encountered that when messages come in from a second sender, the whole communication stops working. The service then does not react to a single connection until you restart it.
public class TCPIP
{
public static Receiver rc = new Receiver();
public class Receiver
{
public delegate void ReceivedEventHandler(string ReceivedText, string Sender);
public event ReceivedEventHandler Received;
public void Start()
{
System.Threading.Thread th = new System.Threading.Thread(internals);
th.Start();
}
private void internals()
{
TcpListener _listener = new TcpListener(1994);
_listener.Start();
while (true)
{
TcpClient rcclient = _listener.AcceptTcpClient();
StreamReader reader = new StreamReader(rcclient.GetStream());
string msg = "";
while (reader.Peek() > -1)
{
msg += Convert.ToChar(reader.Read()).ToString();
}
Received(msg, rcclient.Client.RemoteEndPoint.ToString().Split(Convert.ToChar(":"))[0]);
// Cleanup
rcclient.Close();
reader.Close();
}
}
Could anybody help me out improving this class to answer connections from multiple endpoints, and to not be occupied after one?
Thank you very much in advance.
Just create a thread when you accept some connection, so if it's blocked will not afect the main program.
Btw you can try AcceptTcpClientAsync to prevent blocking calls.
I'm facing a quite strange problem on Unity 5.2.0f3 64Bits. When I create my own custom class for a TcpClient connection, this one never gets connected. This is my simple class:
protected override void StartClient(string mod, string ip)
{
RunClient(ip, mod);
}
private ManualResetEvent connectDone = new ManualResetEvent(false);
private void connect_done(IAsyncResult ar)
{
connectDone.Set();
}
private void RunClient(string ip_host_name, string mode)
{
try
{
TcpClient client = new TcpClient();
client.BeginConnect(IPAddress.Parse(ip_host_name), 6666, new AsyncCallback(connect_done), client);
connectDone.WaitOne();
//Console.WriteLine("Connected");
SslStream lv_ssl_stream = new SslStream(client.GetStream(), false,
new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
if (authenticate_server(lv_ssl_stream, client))
{
}
else
{
// Console.WriteLine("\nCouldn't authenticate the server");
}
client.Close();
}
catch (Exception e)
{
}
}
This is a custom class which doesn't inherit from MonoBehaviour, because the idea was it to run on a different thread. When I execute the Unity app, the class instance is properly created and also executed (with/out Thread, it's for both the same behaviour).
When the process comes across client.BeginConnect() the AsyncCallback() is fired, but the client.connected is still false.
When I replace client.BeginConnect() with client.Connect() the process will hang there, and when it's not executed in a different thread, the Unity framework just dumps. (Not Responding)
I developed the class first on .Net 2012 and could execute it with all expected results (no errors).
EDIT:
When I create and ran TcpClient.Connect() in MonoBehaviour, the TcpClient gets connected to my server, but this isn't an solution for me as it's a lot of data which is getting returned.
Has somebody faced this type of problem?
Workaround for that issue was to create a normal unity C# script, placing there the whole client code.
Unity is still buggy, because the first time the code was copied, it didn't work but commenting out/in it worked (copied code of RunClient() )...
I have a simple TCP server based on the TcpListener. Since I want to use it in a Windows Form application I made it run in a separate thread as follows:
public void Start() {
this.serverThread = new Thread(new ThreadStart(this.ThreadProcess));
this.serverThread.Name = "Tcp-Server";
this.serverThread.Start();
}
protected void ThreadProcess() {
try
{
IPAddress ipAd = IPAddress.Parse("169.254.42.86");
this.listener = new TcpListener(ipAd, this.port);
this.listener.Start();
Socket mySocket = this.listener.AcceptSocket();
while (true)
{
if (mySocket.Connected)
{
byte[] RecvBytes = new byte[8192];
int byteNo = mySocket.Receive(RecvBytes, RecvBytes.Length, 0);
ASCIIEncoding asen = new ASCIIEncoding();
mySocket.Send(asen.GetBytes("srv reply msg"));
}
else
{
WriteLine("socket not connected.");
}
}
}
finally {
StopListener();
}
}
If I use this server in a console application as:
static void Main(string[] args)
{
try
{
int port = 8001;
Server server = new Server(port);
server.Start();
while (true) {
//server is running in separate thread
}
...
everything works as expected. However, when I try to include it in a Windows-Form Application that starts the server when a button is clicked, the code doesn't work any more. The server thread is being launched, but it doesn't accept any sockets.
Is there something that I am missing? I have been searching high and low on google without result...
Thanks for any help!
Not really an answer but too much to type in the comments:
The easiest way to debug this issue is to simply call the ThreadProcess() method in the same thread:
public void Start() {
ThreadProcess();
//this.serverThread = new Thread(new ThreadStart(this.ThreadProcess));
//this.serverThread.Name = "Tcp-Server";
//this.serverThread.Start();
}
You can then step through your code to see what happens. As soon as you hit the this.listener.AcceptSocket(); line your application will block, but you should be able to connect to it.
Usually the problem is something silly everyone overlooks like the Start() method not being called.
A client need to build several tcp connections to server simultaneously.
My Server's code is below.
while (_running)
{
if (!_listener.Pending())
{
Thread.Sleep(100);
continue;
}
TcpClient client = _listener.AcceptTcpClient();
}
And my client's code is below.
for (int i = 0; i < num; i++)
{
TcpClient tcp = new TcpClient();
tcp.Connect(_server);
}
The first connection is success. But the second connection is failed due to server's no response(Actually server are listening tcp connection).
However, if I add Thread.Sleep(1500) after each of tcp.Connect(), all connections are success. But this situation is only true if there are one client and one server. If there are many clients then how can I ensure each connection that can be accepted by server? Also why I add Thread.Sleep can make such connections succeed?
I had the same task. I looked for canonical implementation of this task for .Net with no luck.
The approach I use now is descibed below.
Main idea
We need listener to receive connection, give the connection to the handler, and as soon as possible start listen for a new connection.
Implementation
AutoResetEvent _stopEvent = new AutoResetEvent(false);
object _lock = new object();
public void StartListening()
{
_listener.BeginAcceptTcpClient(ConnectionHandler, null);
_stopEvent.WaitOne();//this part is different in my original code, I don't wait here
}
public void StopListening()
{
lock(_lock)
{
listener.Stop();
listener = null;
}
_stopEvent.Set();//this part is different in my original code
}
void ConnectionHandler(IAsyncResult asyncResult)
{
lock(_lock)
{
if(_listener == null)
return;
var tcpClient = _listener.EndAcceptTcpClient(asyncResult);
var task = new MyCustomTask(tcpClient);
ThreadPool.QueueUserWorkItem(task.Execute);
_listener.BeginAcceptTcpClient(ConnectionHandler,null);
}
}
I am still not very confident in calling _listener.BeginAcceptTcpClient in ConnectionHandler, but I haven't found alternative way.
Since there are still no satisfied answers and I finally use different approach to handle my case. I found out that using class Socket is faster and more stable than using TcpListener and TcpClient. I tried different approach to use TcpListener and TcpClient. Firstly, I used TcpListener.AcceptTcpClient to listen client with and without TcpListener.Pending but there is still possibly ignoring some client connection. Sencondly, I used asynchronous method, TcpListener.BeginAcceptTcpClient and TcpListener.EndAcceptTcpClient but still no succeeded, still ignoring some client connection. Finally using Socket.Accept instead of TcpListener.AcceptTcpClient, the former one has nearly no delay and really fast to response to client.
I'm using visual studio to program this small TcpServer.
It's really specific. The server listens to port 1234 and is located on IP 127.0.0.1
Our teachers gave us a program that tries to connect to that port on that IP when you click "connect". It's working for everyone else, so it must be a coding error on my part.
When I click connect, the program sends the word "GET" over the stream, to which I have to respons with a list of allready connected IP-adress and then a newline containing only a .
When I disconnect, the program sends the word "REM" and I simply have to remove if from my list(which is a generic list)
I have a class TCPServer(we had to make our own), which has this as main code:
this.tl = new TcpListener(IPAddress.Any, PORT);
tl.Start();
while(true)
{
TcpClient tcl = tl.AcceptTcpClient();//here the server will wait forever untill someone connects, meaning the "new Thread" statement is never reached untill someone connects.
TcpHelper th = new TcpHelper(tcl,conf);
new Thread(new ThreadStart(th.Start)).Start();//should be multi-threaded, not sure if it is.
//t.Start();
}
TcpHelper looks like this(look for the commented text "here's the problem" within the usings):
public class TcpHelper
{
private TcpClient tc;
private IPEndPoint ipe;
private string get;
private Configuration conf;
public TcpHelper(TcpClient tc, Configuration conf)
{
this.tc = tc;
this.conf = conf;
}
public void Start()
{
using (NetworkStream nws = this.tc.GetStream())
{
using (StreamReader sr = new StreamReader(nws))
{
using (StreamWriter sw = new StreamWriter(nws))
{
this.ipe = (IPEndPoint)tc.Client.RemoteEndPoint;
this.conf.List.Add(this.ipe.Address);
bool conn = true;
while (conn)
{
this.get = sr.ReadLine();//here's the problem
switch (this.get)
{
case "GET":
foreach (IPAddress address in this.conf.Lijst)
{
sw.WriteLine(address.ToString());
}
sw.WriteLine(".");
break;
case "REM":
this.conf.List.Remove(this.ipe.Address);
sw.WriteLine("OK.");
conn = false;
break;
default:
break;
}
}
}
}
}
}
#region Properties
public IPEndPoint Ipe
{
get
{
return this.ipe;
}
}
#endregion
}
My guess is that your problem is that you're calling sr.ReadLine(), but the input does not contain a newline, so it's blocked there waiting for a newline that will never come.
you may want to try calling StreamReader.Read 3 times to build up the command string (GET/REM) before you act on it. (Note: 3 times is because all commands are three characters).
Read will return integers, but after checking that they are not -1 (indicating end-of-file), you can cast that integer to a char.
Sorry, maybe I'm not understanding this... Did you write this code?
this.tl = new TcpListener(IPAddress.Any, PORT);
tl.Start();
while(true)
{
TcpClient tcl = tl.AcceptTcpClient();
TcpHelper th = new TcpHelper(tcl,conf);
new Thread(new ThreadStart(th.Start)).Start();
//t.Start();
}
This is going to blow the **** out of any computer. You're looping infinitely, creating new threads on each loop. So, if you create one new thread per loop, and each loop takes one millisecond (lets say its very slow!), in five seconds you've got 5,000 threads. Each trying to listen at the same port.
Try using a single thread. If this is a console app, use Console.ReadLine() to block the main thread until somebody presses the enter key.
With the new information... AcceptTcpClient blocks, but instead of creating a new thread the work should be queued on the ThreadPool.