Diskuze: client server
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.
tato problematika je relativne slozita, ale tvuj kod uz od pohledu nevypada moc pouzitelne. aby zde slo o plnohodnotny chat, je treba aby CLIENT používal (minimalne) 2 vlakna (jedno pro prijem zprav a druhe pro odesilani). SERVER by musel pouzivat tolik vlaken, kolik je klientu plus jedno navic sam pro sebe(v pripade ze chce server rozesilat nejake zpravy sam).
dej sem plne zneni kodu pro klienta a plne zneni kodu pro server (vlozene pres "vlozit kod").
Chatovátek najdeš po netu mraky. Uč se od ostatních
David Hartinger:23.7.2014 16:56
Máš tu na to funkční example v sekci C# pro pokročilé.
vodslon:24.7.2014 8:24
Děkuji za odpovědi, na funkční example jsem koukal, je to moc pěkně a jednoduše napsané, ale původně jsem měl představu, kterou se mi ani nedaří vygooglovat, že to bude fungovat na metodě push. Ve Tvém příkladu máš timer, který kontroluje jeslti nejsou data na serveru, je to funkční řešení, ale měl jsem představu, že jak příjme server data natlačí je všem klientům, kteří je zobrazí.
sadlomaslox25:24.7.2014 13:06
to zni jako producer-consumer pattern, ktery implementuje BlockingCollection
( http://www.codethinked.com/…ercollection )
pokud se rozepises vic o tom co ma server a klient presne delat a umet, tak to
mozna dame spolecne dohromady
vodslon:24.7.2014 16:05
zajímavej odkaz, ale s vlákanam to mám pořešený jedno na straně
serveru a dvě na straně clienta. Zatím mám pracovní verzi, ale už to
dělá co chci. Je X klientů a jeden něco napíše tak se to objeví v okně
všem ostatním. Ted z toho mám v plánu udělat multiplayerové "tančíky" ,
prostě čtvrečky které by se honily po plátně a stříleli po sobě. Mě
baví se takhle učit, že si dám "ukol" a pak googluji čtu a snažím se to
zlepit dohromady, snad je to dobrá cesta.
Rád něco pošlu nebo se něco od Tebe přiučím, když budeš mít na mě
čas
sadlomaslox25:25.7.2014 2:29
neni problem. akorat nechapu jak se ti podarilo rozchodit na jednom vlaknu
server.
jinak ten chat by mel +- vypadat nejak takhle (neni to 100% kod ale ty zakladni
myslenky by tam meli jit videt
CLIENT
static void Main(string[] args)
{
var cli = new TcpClient("localhost", 12345);
var stream = cli.GetStream();
//cteni ze serveru
Task.Factory.StartNew(() =>
{
var reader = new StreamReader(stream);
try
{
while (true)
{
var zp = reader.ReadLine();
if (zp == null)
{
Console.WriteLine("server crash");
return;
}
Console.WriteLine(zp);
}
}
catch (Exception ex)
{
}
});
var writer = new StreamWriter(stream);
writer.AutoFlush = true;
//zapsani jmena
Console.WriteLine("Connected: Chose name:");
var name = Console.ReadLine();
writer.WriteLine(name);
//posilani zprav na server
while (true)
{
string lastMsg = Console.ReadLine();
if (lastMsg == "exit")
break;
try
{
writer.WriteLine(lastMsg);
}
catch (Exception ex)
{
Console.WriteLine("server crash");
break;
}
}
cli.Close();
Console.WriteLine("FINISHED");
Console.ReadLine();
}
SERVER
static void Main(string[] args)
{
var clients = new ConcurrentDictionary<string,TcpClient>();
var server = new TcpListener(12345);
var messages = new BlockingCollection<Tuple<string,string>>();
server.Start(50);
//zpracovani klientu
Task.Factory.StartNew(() =>
{
Console.WriteLine("server started");
while (true)
{
var cli=server.AcceptTcpClient();
Console.WriteLine("CLIENT ACEPTED");
var stream = cli.GetStream();
//cteni z klienta
Task.Factory.StartNew(() =>
{
var reader = new StreamReader(stream);
var name = reader.ReadLine();
clients[name] = cli;
messages.Add(new Tuple<string, string>(name, "... entering ..."));
while (true)
{
string message = null;
try
{
message = reader.ReadLine();
}
catch (Exception ex)
{
message = null;
}
if (message == null)
{
Console.WriteLine(name+" is disconected");
messages.Add(new Tuple<string, string>(name, "... leaving ..."));
clients.TryRemove(name, out cli);
return;
}
messages.Add(new Tuple<string,string>(name,message));
}
});
}
});
//rozesilani vsem
Task.Factory.StartNew(() =>
{
while (true)
{
var mess=messages.Take();
foreach (var c in clients)
{
if (c.Key == mess.Item1)
continue;
try
{
var writer = new StreamWriter(c.Value.GetStream()) {AutoFlush = true};
writer.WriteLine("from {0}:{1}",mess.Item1,mess.Item2);
}
catch (Exception ex)
{
Console.WriteLine(c.Key+" CLIENT DISCONECTED");
messages.Add(new Tuple<string, string>(c.Key, "... leaving ..."));
TcpClient pom;
clients.TryRemove(c.Key, out pom);
}
}
}
});
Console.ReadLine();
server.Stop();
clients.ToList().ForEach(o => o.Value.Close());
}
vodslon:25.7.2014 10:17
Moc pěkný kod, já jsem to sesmolil takto..
namespace ServerNew
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public static string data = null;
delegate void SetTextCallback(string text);
List<string> listzpráv = new List<string>();
private Thread vlakno = null;
private void BtnZapni_Click(object sender, EventArgs e)
{
this.vlakno = new Thread(new ThreadStart(this.thread));
vlakno.Start();
}
private void thread()
{
byte[] bytes = new Byte[1024];
TcpListener listener = null;
try
{
listener = new TcpListener(IPAddress.Any, 8888);
listener.Start();
}
catch (SocketException se)
{
Console.WriteLine(se.ErrorCode + ": " + se.Message);
Environment.Exit(se.ErrorCode);
}
List<TcpClient> klienti = new List<TcpClient>();
while (true)
{
try
{
if (listener.Pending())
{
TcpClient klient = listener.AcceptTcpClient();
klienti.Add(klient);
}
}
catch (Exception)
{
throw;
}
foreach (TcpClient klient in klienti)
try
{
if (klient.GetStream().DataAvailable)
{
Socket s = new Socket(SocketType.Stream,ProtocolType.Tcp);
s = klient.Client;
string věta = PrijmiString(klient);
věta = věta.Substring(0,věta.IndexOf("$"));
listzpráv.Add(věta);
foreach (TcpClient socketiklient in klienti)
{
Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
socket = socketiklient.Client;
data = "";
foreach(string se in listzpráv)
{
data = se;
}
byte[] send = Encoding.UTF8.GetBytes(data);
socket.Send(send);
}
SetText(data);
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
}
public static string PrijmiString(TcpClient klient)
{
NetworkStream stream = klient.GetStream();
byte[] buffer = new byte[1024];
stream.Read(buffer, 0, 1024);
return Encoding.UTF8.GetString(buffer);
}
private void SetText(string text)
{
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text = text;
}
}
}
}
"listener.Pending()" no jo este vedet ze neco takoveho existuje (sem doted zil v domeni ze nic takoveho neni).
jinak ale tohle nedava smysl
foreach(string se in listzpráv)
{
data = se;
}
a ani tohle
Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
socket = socketiklient.Client;
a pak je otazka k zamysleni kolik klientu ocekavas, protoze tady ten kod ti pri jakemkoli poctu aktivnich klientu zabere jeden cely procesor (vytizi cele jedno vlakno) naplno.
vodslon:28.7.2014 8:06
To je uplná blbost: Todle jsem zkoušel, aby se novému klientovi
nakopíroval při připojení celý obsah.
foreach(string se in listzpráv)
{
data = se;
}
Todle vypadá napsané strašně, ale nevěděl jsem, jak to udělat
lépe
Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
socket = socketiklient.Client;
jinak ten pending jsem někde opsal podle videa a strašně mi pomohl, super metoda. Ted z toho jdu zkusit udělat Lodě, tak jsem zvědavej
Zobrazeno 12 zpráv z 12.