Több thread futása egy időben hálózaton

Több thread futása egy időben hálózaton
2009-05-12T23:05:01+02:00
2009-06-17T22:45:03+02:00
2022-11-14T00:30:39+01:00
mrgreko
Sziasztok!

Lenne egy server-kliens programom párom,ami sajnos nem működik megfelelően.Ha két klienst futtatok egyszerre,akkor a második kliens addig nem indul el,amíg az elsővel be nem fejezte a server a kommunikációt!Ergo amíg az első kliensen nem jelentkeznek be,(és hajtódik végre a majd később definiált műveletek egyike),addig a másodikon nem tudnak!
Hogy lehetne megoldani,hogy a két,vagy több szál egy időben fusson?

A server kódja:

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Net; using System.Net.Sockets; using System.Threading; using System.IO; namespace DBServer2 { public partial class Form1 : Form { public string[,] pwd_data; public Socket client; public IPEndPoint clientep; public bool status; public string message; public int users; public static int recv; public static byte[] data = new byte[1024]; public static bool stop; public static IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050); public static Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); public Form1() { InitializeComponent(); Thread startServer = new Thread(new ThreadStart(Client)); startServer.IsBackground = true; startServer.Start(); } public void Client() { newsock.Bind(ipep); newsock.Listen(10); while (!stop) { client = newsock.Accept(); clientep = (IPEndPoint)client.RemoteEndPoint; kiir("Kliens csatlakozott "+Convert.ToString(clientep)+" címről!"); string welcome = "A kapcsolat létrejött!"; data = Encoding.ASCII.GetBytes(welcome); client.Send(data, data.Length, SocketFlags.None); beleptet(); } newsock.Close(); } public void beleptet() { recv = client.Receive(data); string user = Encoding.ASCII.GetString(data, 0, recv); int a = recv; recv = client.Receive(data); string pwd = Encoding.ASCII.GetString(data, 0, recv); int b = recv; FileStream fs = new FileStream("proba.txt", FileMode.Open, FileAccess.Read); StreamReader r = new StreamReader(fs); users = Convert.ToInt32(r.ReadLine()); pwd_data = new string[users, 2]; for (int i = 0; i < users; i++) { pwd_data[i, 0] = r.ReadLine(); pwd_data[i, 1] = r.ReadLine(); if (pwd_data[i, 0] == user && pwd_data[i, 1] == pwd) { status = true; break; } else { status = false; } } if (status == true) { kiir("A belépés sikeres!"); message = "ok"; data = Encoding.ASCII.GetBytes(message); client.Send(data, data.Length, SocketFlags.None); } else { kiir("A belépés sikertelen!"); message = "not"; data = Encoding.ASCII.GetBytes(message); client.Send(data, data.Length, SocketFlags.None); beleptet(); } } public void kiir(string msg) { listBox1.Items.Add(msg); listBox1.Refresh(); } private void vege(object sender, EventArgs e) { stop = true; Application.Exit(); } } }
A kliens kódja:

using System; using System.Linq; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Net; using System.Net.Sockets; namespace DBClient { public partial class Form1 : Form { int recv; byte[] data = new byte[1024]; IPEndPoint ipep = new IPEndPoint( IPAddress.Parse("192.168.1.101"), 9050); Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); public Form1() { InitializeComponent(); start_client(); } public void start_client() { server.Connect(ipep); recv = server.Receive(data); label1.Text = (Encoding.ASCII.GetString(data, 0, recv)); } private void click(object sender, EventArgs e) { server.Send(Encoding.ASCII.GetBytes(textBox1.Text)); server.Send(Encoding.ASCII.GetBytes(textBox2.Text)); recv = server.Receive(data); string message = (Encoding.ASCII.GetString(data, 0, recv)); if (message == "ok") { label1.Text = ("A belépés sikeres!"); Form ablak = new Form2(); ablak.ShowDialog(); } else { label1.Text = ("A belépés sikertelen!"); } } } }
Mutasd a teljes hozzászólást!
Aztán megintcsak egy külön osztály az általad megírt PseudoThread.A formon pedig létrehozok egy MyServer objektumot,amit átadok egy PseudoThread típusú objektumnak,aminek a Listen metódusa hajtódik végre minden egyes kliensre?!Remélem jól értelmeztem a dolgokat.

Igen, így gondoltam.

Az a helyzet, hogy szívesen segítek, csak nem ebben a pillanatban. Ha ráér később, szívesen összedobok addig egy kis példakódot, amiből már meg tudod csinálni a feladatod.

Addig is annyit mondanék, hogy:
Van három fő osztály, amit implementálnod kell:
-PseudoThread
-Server
-Client

A PseudoThread-et a Server "figyelő"(*) metódusában példányosítod kérésenként, amikor akceptálódik egy újabb kérés.

(*): Amely pl. egy

while(true) { //Metódusok... }
formájú.

Ebből a Client mondjuk lehet egy formban példányosítva, de akár ki is dumpolhatod a kommunikáció eredményét a sztenderd kimenetre konzolban.

Viszont azt is érdemes számításba venni, ha és amennyiben kliensen is szükség van háttérben állandóan futó ellenőrzésre, akkor ott is érdemes több szállal dolgozni.
Mutasd a teljes hozzászólást!

  • Szerver csak akceptálja a kéréseket, és indítson el egy új szálat melyben a klienssel foglalkozik...
    Mutasd a teljes hozzászólást!
  • Sajnos elég kezdő vagyok a többszálú programozásban,tudnál esetleg konkrét kódot írni,vagy azt,hogy hol kellene módosítanom?
    Mutasd a teljes hozzászólást!

  • while (!stop) { client = newsock.Accept(); //Itt hozz létre egy új szálat new MyThread(client).start; clientep = (IPEndPoint)client.RemoteEndPoint; kiir("Kliens csatlakozott "+Convert.ToString(clientep)+" címről!"); string welcome = "A kapcsolat létrejött!"; data = Encoding.ASCII.GetBytes(welcome); client.Send(data, data.Length, SocketFlags.None); beleptet(); }
    Beleírtam kommentbe, szerintem hol kéne módosítani.
    Szintaxis nem biztos hogy jó, Javaban írtam ilyeneket...
    A MyThread osztály pedig lehetne olyan Thread leszármazott, amelyik Socket-ot kap paraméterül. Kzedőlökésnek ennyit tudok javsolni, majd a penge C#-osok tovább segítenek.
    Mutasd a teljes hozzászólást!
  • Próbálkoztam a MyThread osztály létrehozásával,de nem igazán akar összejönni!Nem tudna esetleg vki egy konkrét C#-os megvalósítást? Azért természetesen köszönöm a segítséget!
    Mutasd a teljes hozzászólást!
  • Ezen az oldalon van egy példa. Ott szépen látszik a lényeg.
    Mutasd a teljes hozzászólást!
  • Kimásolom a kódot,lefordítom,és megpróbálom felfogni,hogy mit csinál!
    Mutasd a teljes hozzászólást!
  • Bár a jelenlegi helyzetre ez a megoldás biztosan jó, azért állapodjunk meg abban, hogy egy komolyabb architektúrában a minden klienshez külön szál elmélet nem éppen a legoptimálisabb megoldás. De mivel ha jól emlékszem, ez nem production software lesz, a prof arcába ez is belefér.
    Mutasd a teljes hozzászólást!
  • Mint azt már említettem,nagyon kezdő vok a témában,és őszintén bevallom,most már teljesen belekavarodtam.Már annyi kódót és megvalósítást láttam,hogy nem igazán tudom elképzelni,hogy hogy is kellene kinéznie.

    Eddig,ha egy kliens csatlakozott,a további klienseknek még a FORM-ja sem jelent meg,amíg az elsővel tartott a kummonikáció!
    Most módosítottam egy kicsit a kódon,így megjelennek a FORM-ok,de csak az utoljára csatlakozott kliensel tud kommunikálni a szerver:

    Kód:

    public void Client() { newsock.Bind(ipep); newsock.Listen(10); while (!stop) { client = newsock.Accept(); Thread newClient = new Thread(new ThreadStart(proba)); newClient.Start(); } } public void proba() { clientep = (IPEndPoint)client.RemoteEndPoint; kiir("Kliens csatlakozott " + Convert.ToString(clientep) + " címről!"); string welcome = "A kapcsolat létrejött!"; data = Encoding.ASCII.GetBytes(welcome); client.Send(data, data.Length, SocketFlags.None); beleptet(); }

    Igazából csak próbálkozok,nem akarom feladni,de már teljes a káosz!
    Mutasd a teljes hozzászólást!
  • Persze hogy csak egy klienssel tud kommunikálni. A csatlakozott klienseket reprezentáló Socekt-okat tárolni kell.

    A Szerverben pl. tárolj egy Socket-okat tartalmazó vektort, a "szál"-osztályban adj át egy referenciát a szerverre, és a szálból hívd meg a szerver egy olyan metódusát, amely az összes kliensnek egymás után elküldi amit kell.

    Tehát összefoglalva:
    A szerverbe csinálj egy Socket-okból álló vektort.
    Vector<Socket> ? pontosan nem vágom a C# szontaktikát.

    Valamint egy metódust,pl
    "sendToAllClients(String msg)"

    amely végigmegy előbbi vektor elemein, és mindegyiknek elküldi msg-t.
    Mutasd a teljes hozzászólást!

  • public class PseudoThread { private MyServer server; private Socket socket; public PseudoThread (MyServer ms, Socket s) { this.server = server; this.socket = s; } public void Listen() { //Itt olvasol a socket-ról, msg //nevű stringbe beteszed, és : server.sendToAllClients(msg); } } PseudoThread pt = new PseudoThread (server,client); new Thread (new ThreadStart (pt.Listen)).Start();

    MyServer legyen egy különálló osztály(inkább ne ágyazd a formba, hanem tedd egy kólön classba).
    Mutasd a teljes hozzászólást!
  • Köszönöm szépen!Most mennem kell órára,de este remélem lesz időm kipróbálni,majd jelentkezem az eredménnyel!
    Mutasd a teljes hozzászólást!
  • Most értem haza,és nézegetem a kódodat.Ami nem igazán tiszta,hogy akkor melyik rész kerüljön a külön Myserver osztályba?
    pl:
    int recv; byte[] data = new byte[1024]; IPEndPoint ipep = new IPEndPoint( IPAddress.Parse("192.168.1.101"), 9050); Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); Thread startServer = new Thread(new ThreadStart(Client)); startServer.IsBackground = true; startServer.Start(); } public void Client() { newsock.Bind(ipep); newsock.Listen(10); while (!stop) { client = newsock.Accept(); Thread newClient = new Thread(new ThreadStart(proba)); newClient.Start(); } } public void proba() { clientep = (IPEndPoint)client.RemoteEndPoint; kiir("Kliens csatlakozott " + Convert.ToString(clientep) + " címről!"); string welcome = "A kapcsolat létrejött!"; data = Encoding.ASCII.GetBytes(welcome); client.Send(data, data.Length, SocketFlags.None); beleptet(); }

    Aztán megintcsak egy külön osztály az általad megírt PseudoThread.A formon pedig létrehozok egy MyServer objektumot,amit átadok egy PseudoThread típusú objektumnak,aminek a Listen metódusa hajtódik végre minden egyes kliensre?!Remélem jól értelmeztem a dolgokat.

    Az üzenetküldéssel pontosítanék,nem kell az összes kliensnek elküldeni,hanem feldolgozás után egy arra adott választ a küldő kliensnek kell visszaküldeni.Eddig pont ezzel volt a probléma,hogy a bejelentkezés után,amíg a szerver üzenetet vár a klienstől (művelet választás),addig újabb kliens nem tudott bejelentkezni.

    Mutasd a teljes hozzászólást!
  • Aztán megintcsak egy külön osztály az általad megírt PseudoThread.A formon pedig létrehozok egy MyServer objektumot,amit átadok egy PseudoThread típusú objektumnak,aminek a Listen metódusa hajtódik végre minden egyes kliensre?!Remélem jól értelmeztem a dolgokat.

    Igen, így gondoltam.

    Az a helyzet, hogy szívesen segítek, csak nem ebben a pillanatban. Ha ráér később, szívesen összedobok addig egy kis példakódot, amiből már meg tudod csinálni a feladatod.

    Addig is annyit mondanék, hogy:
    Van három fő osztály, amit implementálnod kell:
    -PseudoThread
    -Server
    -Client

    A PseudoThread-et a Server "figyelő"(*) metódusában példányosítod kérésenként, amikor akceptálódik egy újabb kérés.

    (*): Amely pl. egy

    while(true) { //Metódusok... }
    formájú.

    Ebből a Client mondjuk lehet egy formban példányosítva, de akár ki is dumpolhatod a kommunikáció eredményét a sztenderd kimenetre konzolban.

    Viszont azt is érdemes számításba venni, ha és amennyiben kliensen is szükség van háttérben állandóan futó ellenőrzésre, akkor ott is érdemes több szállal dolgozni.
    Mutasd a teljes hozzászólást!
  • "while(true)
    {
    //Metódusok...
    }
    formájú. "

    using System.Threading; ... new Timer((object obj) => { ...metódus hívások... }).Change(0, 100);
    Mutasd a teljes hozzászólást!
  • Köszönöm,a példakód sokat segítene.Egy hónap múlva kellene felmutatnom vmit,igazából a funkciók már meg vannak,csak ez a rész hiányos!
    Mutasd a teljes hozzászólást!
  • Köszönöm a linkeket,átnézem őket,de mivel angol,eltarthat egy ideig.
    Mutasd a teljes hozzászólást!
  • Sajnos a vizsgaidőszakom elhúzódott,így most jutott időm foglakozni megint a problémával.Közben a rendszer felszólított,hogy zárjam le a témát,így a legtöbbet hozzászólónak ítéltem a pontokat.Természetesen mindenkinek köszönöm a segítséget!
    Mutasd a teljes hozzászólást!
Tetszett amit olvastál? Szeretnél a jövőben is értesülni a hasonló érdekességekről?
abcd