Diskuze: client server

C# .NET .NET (C# a Visual Basic) client server American English version English version

Avatar
vodslon
Člen
Avatar
vodslon:

Ahoj,

Učím se a napadlo mě udělat něco jako chat a vyzkoušer server - client.
Řekněme něco jako chat. Podle netu jsem se rozhodl pro řešení využívající třídu System.Net.Socket . Spoustu se mi toho podařilo, až vlastně pro mě na tu nejdůležitější věc, pokud se něco změní na serveru (příjde tam nová zpráva) aby to server rozeslal všem připojeným klientům. Všechny moje pokusy vyhořely.
Zkoušel jsem po připojení přidat socket do listu, který projíždím foreach s podmínkou if connected a stejně nic. Háže mi to chybu "Software v hostitelském počítač ukončil vytvořené připojení".

Třeba to tu někdo řešil a bude umět poradit. Děkuji

byte[] bytes = new Byte[64];
IPHostEntry ipHostInfo = Dns.Resolve(Dns­.GetHostName());
IPAddress ipAddress = ipHostInfo.Ad­dressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAd­dress, 8888);
Socket listener = new Socket(Addres­sFamily.Inter­Network, SocketType.Stream, ProtocolType.Tcp);
try
{
listener.Bind(lo­calEndPoint);
listener.Listen(10);
data = null;
// Start listening for connections.
while (true)
{
// Program is suspended while waiting for an incoming connection.
Socket handler = listener.Accept();
// An incoming connection needs to be processed.
soc.Add(handler);
while (true)
{
bytes = new byte[1024];
int bytesRec = handler.Recei­ve(bytes);
data += Encoding.UTF8­.GetString(by­tes, 0, bytesRec);
data += Environment.New­Line;
break;
}
// Show the data on the console.
//SetText(data);
string a ="";
// Echo the data back to the client.
byte[] msg = Encoding.UTF8­.GetBytes("zprá­vy");
foreach (Socket s in soc)
{
if (s.Connected == true)
{
s.Send(msg);
}
}
SetText(a);
//handler.Sen­d(msg);
//handler.Shut­down(SocketShut­down.Both);
//handler.Close();
}

 
Odpovědět 23.7.2014 15:51
Avatar
KlimiCZ
Člen
Avatar
Odpovídá na vodslon
KlimiCZ:

Je tu tlačítko vložit kod

Nahoru Odpovědět  +1 23.7.2014 16:02
Nesnaž se zakrýt něco, co jsi provedl úmyslně. Svět je tak malý, že dotyčný se to stejně dozví.
Avatar
sadlomaslox25:

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").

 
Nahoru Odpovědět  +1 23.7.2014 16:41
Avatar
Milan Křepelka
Redaktor
Avatar
Milan Křepelka:

Chatovátek najdeš po netu mraky. Uč se od ostatních

http://www.codeproject.com/…-TCP-Sockets

 
Nahoru Odpovědět 23.7.2014 16:51
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na vodslon
David Čápka:

Máš tu na to funkční example v sekci C# pro pokročilé.

Nahoru Odpovědět 23.7.2014 16:56
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
vodslon
Člen
Avatar
Odpovídá na David Čápka
vodslon:

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í.

 
Nahoru Odpovědět 24.7.2014 8:24
Avatar
Odpovídá na vodslon
sadlomaslox25:

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 ;)

 
Nahoru Odpovědět 24.7.2014 13:06
Avatar
vodslon
Člen
Avatar
Odpovídá na sadlomaslox25
vodslon:

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 :))

 
Nahoru Odpovědět 24.7.2014 16:05
Avatar
Odpovídá na vodslon
sadlomaslox25:

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());
}
 
Nahoru Odpovědět 25.7.2014 2:29
Avatar
vodslon
Člen
Avatar
Odpovídá na sadlomaslox25
vodslon:

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;
            }
        }
    }


}
 
Nahoru Odpovědět 25.7.2014 10:17
Avatar
sadlomaslox25:

"listener.Pen­ding()" no jo este vedet ze neco takoveho existuje :D (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.

 
Nahoru Odpovědět 25.7.2014 13:48
Avatar
vodslon
Člen
Avatar
Odpovídá na sadlomaslox25
vodslon:

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(Socket­Type.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 :)

 
Nahoru Odpovědět 28.7.2014 8:06
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 12 zpráv z 12.