Avatar billede doomstone-dk- Nybegynder
17. april 2009 - 14:42 Der er 5 kommentarer og
1 løsning

Multi Thread Server

Jeg har siddet og leget lidt med at lave en class som kan bruges som en base til netwærks programmer.

Dog har jeg lidt problemer med det, da det sådan set virker fint, men jeg kan kan ikke rigtig finde ud af hvordan jeg kan få mere information omkring min client ud, som Ip og hvilket port han køre på. Så mit program kan kende bruge fra hinanden. pt køre det sådan at det oprette en thread pr connection, og så kalder events, men et "Client Id" argument.

Hvis i har andre forslag til hvordan jeg kan forbedre min class så sig endelig tid :D

// Kode

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace DoomServer
{
    public class ClientEventArgs
    {
        public int Id;

        public ClientEventArgs(int ClientId)
        {
            this.Id = ClientId;
        }
    }

    public delegate void ClientConnected(ClientEventArgs e);
    public delegate void ClientDisconnected(ClientEventArgs e);
    public delegate void ClientMessage(String Message, ClientEventArgs e);

    class Server
    {
        private TcpListener Listener;
        private TcpClient[] Clients;
        private Thread[] Threads;
        private NetworkStream[] Streams;
        private int MaxThreads = 10;
        private int Latest = 0;
        private int Port;
        private bool Shutdown;
        private int ClientsConnected = 0;
        private bool Running;

        public bool IsRunning
        {
            get
            {
                return Running;
            }
        }

        #region Events
        private static event ClientConnected EventClientConnected;
        private static event ClientDisconnected ClientDisconnected;
        private static event ClientMessage EventClientMessage;

        public void SubscribeClientConnected(ClientConnected eventHandler)
        {
            EventClientConnected += eventHandler;
        }
        public void UnsubscribeClientConnected(ClientConnected eventHandler)
        {
            EventClientConnected -= eventHandler;
        }
        public void SubscribeClientDisconnected(ClientDisconnected eventHandler)
        {
            ClientDisconnected += eventHandler;
        }
        public void UnsubscribeClientDisconnected(ClientDisconnected eventHandler)
        {
            ClientDisconnected -= eventHandler;
        }
        public void SubscribeClientMessage(ClientMessage eventHandler)
        {
            EventClientMessage += eventHandler;
        }
        public void UnsubscribeClientMessage(ClientMessage eventHandler)
        {
            EventClientMessage -= eventHandler;
        }
        #endregion

        public Server(int Port, int MaxThreads)
        {
            this.MaxThreads = MaxThreads;
            this.Port = Port;
        }

        public void Start()
        {
            Running = true;
            ClientsConnected = 0;
            Threads = new Thread[MaxThreads];
            Clients = new TcpClient[MaxThreads];
            Streams = new NetworkStream[MaxThreads];
            Listener = new TcpListener(IPAddress.Any, Port);
            Listener.Start();
            Console.WriteLine("Server started on port " + Port);
            Shutdown = false;

            while (!Shutdown)
            {
                bool found = false;
                try
                {
                    for (int i = 0; i < MaxThreads - 1; i++)
                    {
                        if (Threads[i] == null || !Threads[i].IsAlive)
                        {
                            Console.WriteLine("Awating connection on Thread " + i + " of " + (MaxThreads - 1).ToString());
                            found = true;
                            Clients[i] = Listener.AcceptTcpClient();
                            Console.WriteLine("Client Connected!");
                            Latest = i;
                            Threads[i] = new Thread(HandleClient);
                            Threads[i].Start();
                        }
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine("");
                    Console.WriteLine("---------------------------------");
                    Console.WriteLine("Error (HandleClient):");
                    Console.WriteLine(e.Message);
                    Console.WriteLine("---------------------------------");
                    Console.WriteLine("");
                }
                if (!found)
                {
                    //Console.WriteLine("Unable to find thread.");
                    Thread.Sleep(100);
                }
            }
            try
            {
                Listener.Stop();
                Threads = null;
                Clients = null;
                Streams = null;
                Listener = null;
            }
            catch (Exception e)
            {
                Console.WriteLine("");
                Console.WriteLine("---------------------------------");
                Console.WriteLine("Error (HandleClient):");
                Console.WriteLine(e.Message);
                Console.WriteLine("---------------------------------");
                Console.WriteLine("");
            }
            Running = false;
        }
        public void Stop()
        {
            Shutdown = true;
        }

        private void HandleClient()
        {
            int ClientId = Latest;
            ClientEventArgs ClientData = new ClientEventArgs(ClientId);

            try
            {
                Streams[ClientId] = Clients[ClientId].GetStream();

                // Handle on connection event
                _ClientConnected(ClientData);

                Byte[] bytes = new Byte[1024];
                String data = null;
                int i;

                while ((i = Streams[ClientId].Read(bytes, 0, bytes.Length)) != 0 && !Shutdown)
                {
                    data = null;
                    data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);

                    // Handle on message event
                    _ClientMessage(data, ClientData);
                }
            }
            catch(Exception e)
            {
                Console.WriteLine("");
                Console.WriteLine("---------------------------------");
                Console.WriteLine("Error (HandleClient):");
                Console.WriteLine(e.Message);
                Console.WriteLine("---------------------------------");
                Console.WriteLine("");
            }

            // Handle on disconnected event
            _ClientDisconnected(ClientData);
        }
        public void Send(int ClientId, String Message)
        {
            byte[] msg = Encoding.ASCII.GetBytes(Message);
            Streams[ClientId].Write(msg, 0, msg.Length);
            Console.WriteLine("Sending: " + Message);
        }

        private void _ClientConnected(ClientEventArgs e)
        {
            ClientsConnected++;
            EventClientConnected(e);
        }
        private void _ClientDisconnected(ClientEventArgs e)
        {
            ClientsConnected--;
            ClientDisconnected(e);
        }
        private void _ClientMessage(String Message, ClientEventArgs e)
        {
            if(Message != "\r\n" && Message != "\r" && Message != "\n")
                EventClientMessage(Message, e);
        }

        public override string ToString()
        {
            int clients = 0;
            for (int i = 0; i < MaxThreads - 1; i++)
            {
                if (Threads[i] != null && !Threads[i].IsAlive)
                {
                    clients++;
                }
            }
            return "Server " + clients + " Clients Connected";
        }
    }
}
Avatar billede lasserasch Juniormester
17. april 2009 - 17:26 #1
Læser lige beskeden på min iphone så har ikke nærlæst din kode. Men uanset om det er winforms eller web så kan du ikke ud fra client id se detaljerede informationer om klienten. Men du kunne evt gemme et hashtable på din server med informationer om dine klienter linket op på client id'et. Jeg bruger selv et ligende setup i nogle windows applikationer hvor jeg i stedet for at lave sql forespørgelser direkte fra klienten sender objekter fra en server applikation over sockets forbindelser. Det performer helt vildt godt...

Mvh. Lasse
Avatar billede arne_v Ekspert
19. april 2009 - 02:05 #2
Du kan finde med IP adresse og port for client da TcpClient.

((IPEndPoint)client[i].Client.RemoteEndPoint).Address
((IPEndPoint)client[i].Client.RemoteEndPoint).Port

(utestet)
Avatar billede arne_v Ekspert
19. april 2009 - 02:06 #3
Jeg er meget skeptisk over de fixed size arrays. Jeg tror at du ville være bedre tjent med nogle List<> evt. med nogle Dictionary<>.
Avatar billede arne_v Ekspert
05. juli 2009 - 21:47 #4
doomstone ?
Avatar billede doomstone-dk- Nybegynder
20. juli 2009 - 12:59 #5
Hey Arne_v det var lige det jeg havde brug for, kan du ikke skrive noget som et svar så vi kan lukke denne tråd? :D
Avatar billede arne_v Ekspert
20. juli 2009 - 15:25 #6
svar
Avatar billede Ny bruger Nybegynder

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.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester