Laden...

mehrere TcpListener?

Erstellt von Flashed vor 14 Jahren Letzter Beitrag vor 14 Jahren 2.008 Views
F
Flashed Themenstarter:in
9 Beiträge seit 2009
vor 14 Jahren
mehrere TcpListener?

Hallo,
ich habe um Netzwerk-Programmieren mit C# ein wenig zu lernen einen erweiterten Chat geschrieben.

Bisher läuft alles über die TcpListener und TcpClient Klassen.
Mitlerweile kann ich auch Dateien versenden. Ich erstelle für das Versenden von Dateien einen TcpListener (zusätzlich zu dem "normalen", der für das Chatten zuständig ist).

Jetzt meine Frage :
Ist es sinnfoll, so für zB das Senden von ganzen Dateien einen zusätzlichen TcpListener und TcpClient zu erstellen ( somit auch ein zusätzlicher Port) ?
Oder geht das besser über eine Verbindung?

mfg Flashed

R
164 Beiträge seit 2008
vor 14 Jahren

Ich würde nur einen TcpListener/TcpClient verwenden, weil das weniger Ressourcen verbraucht und nicht so viele Ports blockiert werden. Um zu erkennen, ob eine Datei gesendet wird, kannst du ein Nachrichten-Format erstellen. Gut eignet sich Xml, da im .Net Framework Komponenten für Xml vorhanden sind (XmlReader, XmlWriter).
Zum Beispiel:


<message>
 <content>Hallo</content>
 <file name="Datei.txt">Dateiinhalt</file>
</message>

F
Flashed Themenstarter:in
9 Beiträge seit 2009
vor 14 Jahren

Erstmal danke für die schnelle Antwort 🙂

Ich hab jetzt ein wenig gegoogelt und vieles zu XmlSerializer und Co gefunden.
Da ich mich mit Xml aber gar nicht auskenne versteht ich das kaum 🙁

Ist es mit XmlSerializer möglich ganze Objekte in Xml abzuspeichern und dann zB über Netzwerk zu senden?

Wenn ja, hätte jemand einen kleinen Code-Schnippsel?

1.346 Beiträge seit 2008
vor 14 Jahren

XmlSerializer s = new Serializer(typeof(deineklasse));
s.Serialize(deinstream,deineinstanz);

Gruß pdelvo

F
Flashed Themenstarter:in
9 Beiträge seit 2009
vor 14 Jahren

Das Übertragen funktioniert jetzt zwar, aber er blockiert, bis der Stream geschlossen wird.
Kann ich das irgent wie verhindern, oder muss ich für jede Nachricht einen neuen Stream erzeugen?

Der Client :


            testKlasse tk = new testKlasse();
            
            tk.str = "test";

            StreamWriter strm = new StreamWriter(tcpServer.GetStream());

            XmlSerializer s = new XmlSerializer(typeof(testKlasse));
            s.Serialize(strm, tk);

Der Server :


                Console.WriteLine("recieving");
                
                StreamReader strm = new StreamReader(tcpClient.GetStream());

                testKlasse Response;

                XmlSerializer s = new XmlSerializer(typeof(testKlasse));

                Response = (testKlasse)s.Deserialize(strm);

                Console.WriteLine("testklasse " + Response.str);
2.760 Beiträge seit 2006
vor 14 Jahren

Du solltest jede eingehende Verbindung in einem eigenen Thread behandeln wenn du das singlethreaded machst dann liegt das nicht wirklich in der Natur eines Servers.

Im Beispiel ist ein Server mit einem Clientprogramm das per Kommandozeilenargument einen Dateipfad entgegennimmt und an den Server schickt. Der Server speichert die Datei mit einem Random-Filename und empfängt jede Datei in einem eigenen Thread.

Serverklasse:


    class Program
    {
        static void Main(string[] args)
        {
            Server server = new Server(80);
        }
    }

    public class Server
    {
        private Thread _listenerThread;
        private bool _shutdown = false;

        public Server(int port)
        {
            ParameterizedThreadStart threadStart = new ParameterizedThreadStart(Listen);
            _listenerThread = new Thread(threadStart);

            _listenerThread.Start(port);
        }

        private void Listen(object port)
        {
            TcpListener listener = new TcpListener((int)port);
            listener.Start(10);

            while (!_shutdown)
            {
                TcpClient client = listener.AcceptTcpClient();
                ThreadPool.QueueUserWorkItem(new WaitCallback(AcceptFile), client);
            }
        }

        private void AcceptFile(object state)
        {
            TcpClient client = (TcpClient)state;

            using (NetworkStream stream = client.GetStream())
            {
                string fileName = Path.GetRandomFileName();

                using (FileStream fs = File.Create(fileName))
                {
                    int currentByte = 0;
                    while ((currentByte = stream.ReadByte()) != -1)
                    {
                        fs.WriteByte((byte)currentByte);
                    }
                    fs.Flush();
                }
            }

            client.Close();
        }
    }

[EDIT] Oops, war wohl am Thema vorbei...

Evtl. könnte das Hilfreich sein: [FAQ] Warum blockiert mein GUI? aber beschreib mal näher was genau blockiert..

K
133 Beiträge seit 2009
vor 14 Jahren

Den XmlSerializer solltest du aber im Produkiveinsatz möglichst vermeiden da du mit XML doch schon eine menge chunk versendest. Solltest dir vllt Gedanken über ein eigenes Protokoll machen 😃

F
Flashed Themenstarter:in
9 Beiträge seit 2009
vor 14 Jahren

Natürlich arbeite ich mit mehreren Threads und das GUI blockiert auch nicht, sondern der thead, der die geweilige Nachricht empfängt blockiert, bis der Stream geschlossen wird.
Wie sage ich dem Deserializer das die Nachricht völlstandig angekommen ist?

Ich denke, ich werde erstmal weiter den XmlSerializer benutzen, da ich ganze Objekte versenden möchte.

2.760 Beiträge seit 2006
vor 14 Jahren

Natürlich arbeite ich mit mehreren Threads und das GUI blockiert auch nicht, sondern der thead, der die geweilige Nachricht empfängt blockiert, bis der Stream geschlossen wird.

Deswegen machst du es ja auch in einem eigenen Thread. Deshalb verstehe ich dein Problem gerade nicht.

F
Flashed Themenstarter:in
9 Beiträge seit 2009
vor 14 Jahren

Mein Problem ist, das der Thread des Clients auf dem Server, der die Nachrichten entgegen nimmt und deserialisiert, so lange blockiert, bis der StreamReader geschlossen wird.
Das heißt, dass ich die Nachricht auf dem Server erst dann ausgegen bekomme, wenn der Client die Verbindung wieder abricht.

F
Flashed Themenstarter:in
9 Beiträge seit 2009
vor 14 Jahren

Ich habs jetzt alleine gelöst.
Falls es jemanden interessiert. Ich bin über einen Umweg gegangen und wandel das xml-objekt in einen string um und schreib den über den Netzwerk-Stream.

Der Sender :


           ....
            testKlasse tk = new testKlasse();
            tk.str = "test";

            SendMessage(SerializeObject(tk));
 ....

public String SerializeObject(Object pObject)
        {
            try
            {
                String XmlizedString = null;
                MemoryStream memoryStream = new MemoryStream();
                XmlSerializer xs = new XmlSerializer(typeof(testKlasse));
                XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream,
Encoding.UTF8);
                xs.Serialize(xmlTextWriter, pObject);
                memoryStream = (MemoryStream)xmlTextWriter.BaseStream;
                XmlizedString = UTF8ByteArrayToString(memoryStream.ToArray());
                return XmlizedString;
            }
            catch (Exception e) { System.Console.WriteLine(e); return null; }
        }
private String UTF8ByteArrayToString(Byte[] characters)
        {

            UTF8Encoding encoding = new UTF8Encoding();
            String constructedString = encoding.GetString(characters);
            return (constructedString);
        }

Der Empfänger :

 ...
                while ((strResponse = srReceiver.ReadLine()) != "")
                {
                    
                    // If it's invalid, remove the user
                    if (strResponse == null)
                    {
                        ChatServer.RemoveUser(tcpClient);
                    }
                    else
                    {
                        string Message = strResponse.Substring(17, strResponse.Length - 17);

                        Console.WriteLine("recieving");
                        Console.WriteLine(Message);
                        Console.WriteLine("Deserialisieren");
                        testKlasse Response = (testKlasse)DeserializeObject(Message);
                        Console.WriteLine("testklasse " + Response.str);
                        //ChatServer.AnalyseMessage(Response);

                    }
                }
...
 public Object DeserializeObject(String pXmlizedString)
        {
            XmlSerializer xs = new XmlSerializer(typeof(testKlasse));
            MemoryStream memoryStream = new MemoryStream(StringToUTF8ByteArray(pXmlizedString));
            XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
            return xs.Deserialize(memoryStream);
        }
private Byte[] StringToUTF8ByteArray(String pXmlString)
        {
            UTF8Encoding encoding = new UTF8Encoding();
            Byte[] byteArray = encoding.GetBytes(pXmlString);
            return byteArray;
        }