20. april 2007 - 10:36Der er
29 kommentarer og 1 løsning
socket listener
Hej folkens.
Jeg sidder og skriver på en klient i et sockets miljø..
Jeg har problemer med at få lavet en slags listener som står og lytter på om der kommer data fra min server, men der sendes data fra klienten til serveren... For mig ser det ud som om, at lytte processen, optager streamen i den periode klienten lytter...
Måden jeg har bygget klienten op på er ved hjælp af en klasse med metoderne - EstablishConnection - SendData - RecieveData - CloseConnection
RecieveData ser ud som følger public string RecieveData() { return ClientReader.ReadLine(); }
Nogen der kan give mig et spark i den regtige retning her?
Jeg har en windows form, hvorfra følgende kode eksekveres via en knap. Det får hele applikationen til at fryse...
Hvis der er ikke er data i streamen, og denne så ikke er null (jeg har også prøvet med ""), hvad dælen er den så? Eller er det en helt forkert måde at gribe det an på?
Hvis du laver så clienten kører i en tråd for sig selv, så fryser formen ikke. Kig evt. på denne kode:
using System; using System.Collections.Generic; using System.Text; using System.Net; using System.Net.Sockets; using System.IO; using System.Windows.Forms;
namespace WindowsApplication1 { public class Client { private string ip; private int port; private StreamWriter sw;
public Client(string _ip, int _port) { ip = _ip; port = _port; }
public void Run() { TcpClient client = new TcpClient(ip, port); StreamReader sr = new StreamReader(client.GetStream()); sw = new StreamWriter(client.GetStream());
string line = ""; while (true) { try { line = sr.ReadLine(); } catch { MessageBox.Show("Forbindelse afbrudt!"); Environment.Exit(0); }
MessageBox.Show(line); } } public void Send(string msg) { lock (sw) // lås så der ikke er andre der bruger den { sw.WriteLine(msg); sw.Flush(); } } } }
Den bruges så på denne måde:
private void Form1_Load(object sender, EventArgs e) { Client client = new Client("123.123.123.123", 123); Thread t = new Thread(new ThreadStart(client.Run)); t.Start();
Det skal også lige siges at grunden til du får fejl er fordi clienten ikke har noget at oprette forbindes inden der sendes, når det bliver gjort som jeg viste. Dette kan du løse enten ved at client tråden bruger en delegate til at fortælle din main-tråd hvornår den er færdig med at forbinde eller du kan vendte lidt med at sende noget til serveren og så bruge den "if" der tjekker om sw er null inden der bliver sendt. Lav en button der sender til serveren ved tryk.. så vil du se at det virker:
Serveren er sat til at hvergang der modtaget data fra klient, så skal der også sendes til den. Nu er der bare det ved det, at det kun er hver anden gang der kommer noget igennem... det gælder begge veje..
using System; using System.Net; using System.Net.Sockets; using System.IO;
namespace SocketServer { class Server { TcpListener ServerListener; TcpClient Client; StreamReader ClientReader; StreamWriter ClientWriter;
public void StartServer(string[] args) { int LocalServerPort = Int32.Parse(args[0]); Console.WriteLine("Server is startet\nWaiting for client to connect...");
Hmmm når jeg tester det med den client klasse jeg postede, så virker det fint.. har også prøvet at lade servern svare hver gang der bliver modtaget noget og alle beskeder kommer igennem begge veje...
Kan du måske sige lidt mere om hvad der ikke kommer igennem?
Nu blander jeg mig bare lige lidt i denne post her, men jeg har også lige siddet et par dage og leget med socket forbindelser.
Har fået min kode til at virke ret godt. Den bruger en lidt anden tilgang men det virker 100% og også uden brug af eksterne komponenter osv. Den kunne du jo evt. kigge igennem. Koden er rimelig godt kommenteret og med fungerende eksempler.
Jeg kigger videre på det i eftermiddag når sønnike sover til middag..
lasserasch, tak for eksemplerne. Jeg har lige hurtigt skimtet clienten igennem. Jeg kan se, at der er det den native del at sockets du bruger, hvor jeg bruger higher level abstraction layer. Fordelen ved dette skulle være at kodemængden reduceres og så dette .net socketslag for en del at det slaviske kodearbejde...
Men tak for din interesse... jeg kigger videre på det, også dit materiale
Jeg er ny omkring socket's så det ved jeg ikke rigtig så meget om, men kodemængden da ikke specielt størrere end i overstående kodestumper. Måske lidt, men ikke meget...
Nå, men det virker i hvert fald for mig. Jeg brugte nemlig også lang tid på at sidde og lege med noget ala det du er igang med nu. Kunne bare ikke få det til at virke ordenligt. Men fandt et program på nettet som jeg splittede ad, og det jeg så har lagt op på nettet, er så resultatet af det lille projekt.
Jeg har fået det til at virke nu. Mr. Kill, du skal have point!
Dog har jeg et spørgsmpl på falderebet. I min form har jeg et textboks element. Hvordan får jeg alt det der læses i streamen (fra tråden) skrevet ud heri?
public string ExportDataFromListener() { return ExportData; }
Jeg opretter en delegate og binder den op på en eventhandler. Det virker fint, men når der i min form notificeret om en event, vil jeg gerne at den returnede streng fra metoden ExportDataFromListener udskrives i view.text i min form. Det kan den ikke da hvis er fra en anden tråd - jeg får følgende fejl :
Handling på tværs af tråde er ugyldig: Objektet 'View' blev åbnet fra en anden tråd end den tråd, det blev oprettet i.
Der er et eksempel på det i tcpkommunikation.zip. Og det er også rimelig godt kommenteret.
Men her er basis :
1. Når du får denne "fejl", er det fordi du forsøger at opdatere en kontrol som ligger på din form og er synlig for brugeren. Dette må ikke gøres på tværs af tråde. (Man kan godt slå advarslen fra, men det er absolut ingen løsning. Der er jo en grund til at den er der...)
2. Du skal bruge en delegate til det.
Den definerer du i starten af din kode.
I dette eksempel trækkes en streng med igennem forløbet også. Det er jo ikke altid nødvendigt...
public partial class form1 : Form { delegate void Delegate1(String TXT);
...
3. Du kalder pt. et eller anden void. Og det er her det går galt. Det skal du blive ved med.
Du skal bare tilføje lidt kode :
Her et eksempel på en void som bruger den delegate jeg lige har defineret : Min void forsøger at sætte teksten i en label som ligger på formen. Det får den ikke lov til, hvis der kaldes fra en anden tråd.
private void dinvoid(string TXT) { if (label1.InvokeRequired) { Delegate1 d = new Delegate1(dinvoid); this.Invoke(d, new object[] { TXT }); } else { label1.Text = TXT; }
}
Det er forholdsvis simpelt når man lige fanger pointen i det. Når du opretter en ny reference til "Delegate1", så skal man angive navnet på den void man står i pt, da det jo stadig er den void man vil arbejde med.
Og TXT er bare en String variabel som vi skal bruge. Hvis du ikke har brug for den sletter man jo bare lidt af koden så den ser sådan ud :
public partial class form1 : Form { delegate void Delegate1();
...
private void dinvoid() { if (label1.InvokeRequired) { Delegate1 d = new Delegate1(dinvoid); this.Invoke(d); } else { label1.Text = "JUHUUEEE.... DET VIRKER!"; }
Så fik jeg den Jeg prøvede med både delegastes og events samtidig. Nu kan jeg snuppe data fra én tråd over til en anden.
Dog driller event handleren mig. Jeg har jo bekendt en tråd hvori jeg har min listener, som konstant står oglytter på data, jeg vil så gerne at denne smider en event når der er data..
Så virker det endelig for mig :) dog undre det mig, at jeg "kun" kan udskrive til f.eks. en messagebox og ikke en label...
via følgende public void ManageControls(string message) { //label1.Text = message; MessageBox.Show(message); }
dette er i min form. Den trigger på et event fra en anden klasse jeg har. Gennem min delegate overfører jeg så data, som jeg udskriver i en messageboks, men det virker bare ikke i min label...
Det forekommer mig simpelt at arbejder med de her kontroller, men den her kan jeg dælme ikke gennemskue....
Igen kan jeg kun råde dig til at studere mit førnævnte eksempel grundigt. Den laver netop en udskrivning til controls på en form.
Og ja det er underligt, for det skal virke. Du er sikker på at du ikke rende ind i en exception? MessageBox kræver jo ikke nogen invoke da den ikke ligger på formen som en control. Det gør din label... Så jeg tror ikke du får invoked korrekt. Tjek din output og se om der står noget om en exception der...
/Lasse
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.