NOVINKA - Online rekvalifikační kurz Java programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.
NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!
Avatar
Jan Mrva
Člen
Avatar
Jan Mrva:30.9.2017 22:33

Zdravim,
prosim Vas, potreboval by som pomoct. Potrebujem v c# spravit TCP server, ktory pocuva na porte XXX. Ked sa klient pripoji, server mu bude automaticky zasielat data napr. datum kazdu sekundu, pricom ked sa klient odpoji (zatvori spojenie), server prestane posiealt data a bude cakat na pripojenie dalsieho klienta. Klient neposiela do serveru ziadne data. (okrem zatvorenia spojenia).
Cez blocking funkciu read neprichadza riesenie v uvahu, kedze klient neposiela serveru ziadne data. V C som to kedysi riesil prepnutim socketu do non-blocking state, pricom som mohol pouzit funkciu read. V C# som ale nic taketo nenasiel.
Vdaka

 
Odpovědět
30.9.2017 22:33
Avatar
Petr Šťastný
Tvůrce
Avatar
Petr Šťastný:30.9.2017 23:11

Mělo by to jít takhle (nezkoušel jsem):
CLIENT:

TcpClient client = new TcpClient();
client.Connect(ip, 9999); // ip serveru, port
NetworkStream stream = client.GetStream();
while (true) // Nebo dokud nebudes chtit zavrit komunikaci
{
    string response = String.Empty;
    byte[] Cdata = new byte[256];
    int bytes = stream.Read(Cdata, 0, Cdata.Length); // Tady mas data
    response = Encoding.ASCII.GetString(Cdata, 0, bytes); // Kdybys posilal treba text, takhle to hodis do stringu
    Console.WriteLine("Received string: " + response);
}
stream.Close(); // Odpojeni klienta
client.Close();

SERVER:

TcpListener server = new TcpListener(IPAddress.Parse(ip), 9999); //ip = IP adresa serveru, 9999 je port
server.Start();

    TcpClient myClient = server.AcceptTcpClient();
    NetworkStream myStream = myClient.GetStream();
    while (true) // Dokud budes neco posilat
    {
            byte[] msg = System.Text.Encoding.ASCII.GetBytes("data"); // Data co budes posilat. Budto byte[], nebo muzes posilat string

            myStream.Write(msg, 0, msg.Length);
    }

    // Vypni server (nebo skoc na zacatek a cekej na dalsiho klienta)
    myClient.Close();
Editováno 30.9.2017 23:14
 
Nahoru Odpovědět
30.9.2017 23:11
Avatar
Jan Mrva
Člen
Avatar
Odpovídá na Petr Šťastný
Jan Mrva:1.10.2017 12:29

Ahoj,
nie, tak ako pises to nepojde. Neviem z uvedeneho zistit ci sa pocas komunikacie odpojil alebo nie. Ak by som pouzil read ktory by to cital, zablokoval by som cely cyklus...
Write na serveri myStream.Write(msg, 0, msg.Length); nezneguje while(true)...

 
Nahoru Odpovědět
1.10.2017 12:29
Avatar
Petr Šťastný
Tvůrce
Avatar
Odpovídá na Jan Mrva
Petr Šťastný:1.10.2017 13:08

Tak to asi budeš asi muset udělat tak, že

  1. Client pošle serveru zprávu o tom, že se odpojuje (když třeba uživatel zavře aplikaci klienta)

nebo

  1. Client musí posílat serveru každých x vteřin zprávu, že je online. Jakmile přestane, server ho odpojí (kdyby třeba vypadl internet)

Posílání zpráv serveru: [CLIENT]

byte[] data = Encoding.ASCII.GetBytes("Jsem online");
stream.Write(data, 0, data.Length);

Přijímání zpráv od clienta: [SERVER]

string zprava;
byte data = new byte[256];
while ((i = myStream.Read(data, 0, data.Length)) != 0)
{
zprava = System.Text.Encoding.ASCII.GetString(data, 0, i);
Console.WriteLine("Received string: " + zprava);
}
Editováno 1.10.2017 13:10
 
Nahoru Odpovědět
1.10.2017 13:08
Avatar
Jan Mrva
Člen
Avatar
Jan Mrva:1.10.2017 13:26

Nemozem ovplyvnit klientsku aplikaciu. Ta je dana.
Klient sa pripoji a caka na data ktore mu server posle. Ked mu nieco posle, spracuje ich a caka na dalsie alebo ak mu stacia tak zatvori spojenie (read vrati 0). Read nemozem vracat lebo je to blocking funkcia.

 
Nahoru Odpovědět
1.10.2017 13:26
Avatar
Martin Dráb
Tvůrce
Avatar
Odpovídá na Jan Mrva
Martin Dráb:1.10.2017 13:41

Nerozumím, proč mluvíš o Read, když klienta nemůžeš ovlivnit. Myslíš tím tedy volání Write na serveru (protože podle toho, co píšeš, tak server jen zapisuje a klient jen čte)?

Mělo by být možné nastavit na Write nějaký timeout, který když vyprší, funkce vrátí nějakou hodnotu nebo vyhodí výjimku. Stejně musíš řešit případy, kdy spojení spadne "samo od sebe".

Nahoru Odpovědět
1.10.2017 13:41
2 + 2 = 5 for extremely large values of 2
Avatar
Jan Mrva
Člen
Avatar
Odpovídá na Martin Dráb
Jan Mrva:1.10.2017 14:22

Klienta nemozem ovplyvnit, ten je dany.
Klient sa pripoji na Server a caka na data. Server mu ich posle a ma skontrolovat, ci je klient stale pripojeny. Ak nie, server ukonci cyklus a caka na nove spojenie.
Read som pouzival pretoze cez neho viem zistit, ci je velkost prijatych dat <1. V tom pripade viem, ze klient sa odpojil.

 
Nahoru Odpovědět
1.10.2017 14:22
Avatar
Martin Dráb
Tvůrce
Avatar
Odpovídá na Jan Mrva
Martin Dráb:1.10.2017 16:33

Podle tohoto
https://msdn.microsoft.com/…vs.110).aspx

nastavíš vlastnost SendTimeout instance TcpClient, kteoru dostaneš z acceptu, na nějakou rozumnou hodnotu (třeba pět vteřin = 5000). Pokud se volání Write zablokuje na delší dobu, vyhodí výjimku SocketException. Tím se zároveň dozvíš, že klient se pravděpodobně odpojil (ať už chtěl, nebo prostě spadlo připojení).

Nahoru Odpovědět
1.10.2017 16:33
2 + 2 = 5 for extremely large values of 2
Avatar
David Oczka
Tvůrce
Avatar
Odpovídá na Jan Mrva
David Oczka:5.10.2017 18:38

Další relativně jednoduchá kontrola je, že se pokusíš zapsat nic do toho streamu... Nevím, jak moc je to správné řešení, ale funguje to dobře. Hlavně jde o to, že tím nic neovlivníš...

try
{
   client.GetStream().Write(new byte[] { }, 0, 0);
}
catch
{
   // Stream je uzavřený a klient odpojený
}
Editováno 5.10.2017 18:38
 
Nahoru Odpovědět
5.10.2017 18:38
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 9 zpráv z 9.