C# - szalejący wątek obciąża w 100% procesor


(northwest) #1

Witam,

Mam problem z aplikacją wątkową (aplikacja klient-serwer). Program po uruchomieniu i wystartowaniu wątku pracuje normalnie, ale w pewnym momencie (najczęściej po odłączeniu klienta od serwera) zaczyna obciążać w 100% processor... W przypadku 2,3 klientów robi się masakra... kod wygląda tak:

Plik glowny.sc:

namespace Serwer

{


    class Program

    {

        static void Main(string[] args)

        {

            int sPort = 8081;          

            Hashtable klienci = new Hashtable();    

            try

            {

                IPAddress ip = IPAddress.Parse("192.168.0.1"); //169.254.27.49

                TcpListener serwer = new TcpListener(ip, sPort);

                serwer.Start();

                Console.WriteLine("Serwer is started");

                while (true)

                {

                    TcpClient client = serwer.AcceptTcpClient();

		            Console.WriteLine("polaczono");

                    new Thread(new ThreadStart( new ConnectionSession(client).run)).Start();

                }

            }

            catch (Exception see)

            {

                Console.WriteLine("Błąd : " + see.Message);

            }

        }

    }

}

Plik ConnectionSession.cs:

class ConnectionSession

{

    protected int ClientID = 0;

    private TcpClient Client;


    public ConnectionSession(TcpClient client)

    {

        Client = client;

    }


    public static int ByteIndexOf(byte[] searched, byte[] find, int start)

	{

        bool matched = false;

        for (int index = start; index <= searched.Length - find.Length; ++index)

        {

            matched = true;

            for (int subIndex = 0; subIndex < find.Length; ++subIndex)

            {

                if (find[subIndex] != searched[index + subIndex])

                {

                    matched = false;

                    break;

                }

            }

            if (matched)

            {

                return index;

            }

        }

        return -1;

    }

    const int BUF_LEN = 256;

    const int SYNC_FRAME_LEN = 8;


    private bool ReadSynchroHeader()

    {

        byte[] myReadBuffer = new byte[BUF_LEN];

        byte[] sync_frame = new byte[SYNC_FRAME_LEN];

        int i;

        for (i = 0; i < SYNC_FRAME_LEN; i++) {

            sync_frame[i] = (byte)(i+0x80);

        } 

        String s;

        uint read_ptr = 0, write_ptr = 0;

        if (Client.Connected)

        {

            StringBuilder dane = new StringBuilder();

            int numberOfBytesRead = 0, numberOfBytesToRead = 0;


            NetworkStream myNetworkStream = Client.GetStream();

            while (Client.Connected)

            {

                try

                {

                    if (myNetworkStream.CanRead)

                    {

                        numberOfBytesToRead = (int)(write_ptr >= read_ptr ? BUF_LEN - write_ptr : read_ptr - write_ptr);

                        myNetworkStream.ReadTimeout = 1000;

                        if (myNetworkStream.DataAvailable)

                        {

                            numberOfBytesRead = myNetworkStream.Read(myReadBuffer, (int)write_ptr, numberOfBytesToRead);

                            write_ptr = (uint)((write_ptr + numberOfBytesRead) % BUF_LEN);

                        }

                        while (read_ptr < write_ptr) { 

                            if (myReadBuffer[read_ptr] == 0xFA || myReadBuffer[read_ptr] == '$') {

                                break;

                            }

                            read_ptr = (read_ptr + 1) % BUF_LEN;

                        }

                        if (read_ptr == write_ptr) { 

                            read_ptr = write_ptr = 0;

                            continue;

                        }

                        try

                        {

                            if (myReadBuffer[read_ptr] == 0xFA)

                            {

                                if ((write_ptr - read_ptr + BUF_LEN) % BUF_LEN < SYNC_FRAME_LEN)

                                {

                                    continue;

                                }

                                for (i = 0; i < SYNC_FRAME_LEN; i++)

                                {

                                    sync_frame[i] = myReadBuffer[(read_ptr + i) % BUF_LEN];

                                }

                                if (sync_frame[1] != 0xF8)

                                {

                                    s = "";

                                    for (i = 0; i < SYNC_FRAME_LEN; i++) {

                                        s += String.Format("{0:X2} ", sync_frame[i]);

                                    }

                                    throw new FormatException("RE01 "+s);

                                }

                                int syncID = myReadBuffer[(read_ptr + 2) % BUF_LEN] | (myReadBuffer[(read_ptr + 3) % BUF_LEN] << 8);

                                uint unitID = (uint)myReadBuffer[(read_ptr + 4) % BUF_LEN] | (uint)(myReadBuffer[(read_ptr + 5) % BUF_LEN]) << 8 |

                                    (uint)(myReadBuffer[(read_ptr + 6) % BUF_LEN]) << 16 | (uint)(myReadBuffer[(read_ptr + 7) % BUF_LEN]) << 24;

                                Console.WriteLine(String.Format("Odebrano sync: {0:X4}, UnitID {1:X8}\r\n", syncID, unitID));

                                SendMessage(sync_frame, SYNC_FRAME_LEN);

                                // przesuń wskaźnik odczytu (cała ramka odczytana)

                                read_ptr = (read_ptr + SYNC_FRAME_LEN) % BUF_LEN;

                            }

                            else if (myReadBuffer[read_ptr] == '$' || (myReadBuffer[read_ptr] >= '0' && myReadBuffer[read_ptr] <= '9'))

                            {

                                uint ptr = read_ptr+1;

                                while (ptr < write_ptr)

                                {

                                    if (myReadBuffer[ptr] == '\n')

                                    {

                                        break;

                                    }

                                    else if (myReadBuffer[ptr] == '$') {

                                        s = "";

                                        for (i = 0; i < ptr - read_ptr + 5; i++) {

                                            s += String.Format("{0:X2} ", myReadBuffer[(read_ptr + i)%BUF_LEN]);

                                        }

                                        throw new FormatException("RE04 " + s);

                                    }

                                    ptr = (ptr + 1) % BUF_LEN;

                                }

                                if (ptr == write_ptr)

                                {

                                    continue;

                                }

                                byte[] buf = new byte[256];

                                byte[] b = Encoding.ASCII.GetBytes("Odebrano ramkę: ");

                                for (i = 0; i < b.Length; i++)

                                {

                                    buf[i] = b[i];

                                }

                                for (i = 0; i < (write_ptr - read_ptr + BUF_LEN) % BUF_LEN; i++)

                                {

                                    buf[16 + i] = myReadBuffer[(read_ptr + i) % BUF_LEN];

                                }

                                SendMessage(buf, i + 16);



                                read_ptr = (ptr + 1) % BUF_LEN;

                            }

                        }

                        catch (FormatException ex) { 

                            read_ptr = (read_ptr + 1) % BUF_LEN;

                        }

                    }

                }

                catch (Exception se)

                {

                    Console.WriteLine("Klient odłączony");

                }


            }


        }

        else

        {

            Console.WriteLine("Klient odłączony");

        }

        return true;

    }


    public static byte[] StrToByteArray(string str)

    {

        System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();

        return encoding.GetBytes(str);

    }

    private void ReadInfo()

    {

        if (Client.Connected)

        {

            StreamReader rclient = new StreamReader(Client.GetStream());


            while (true)

            {

                try

                {

                    string dane = rclient.ReadLine();

                    Console.WriteLine(dane);


                }

                catch (Exception se)

                {

                    Console.WriteLine("Błąd : " + se.Message);

                }

            }

        }

    }

    private void SendMessage(string message)

    {

        if (String.IsNullOrEmpty(message))

            message = "\n";


        byte[] metaBuffer = Encoding.ASCII.GetBytes(message);

        Console.WriteLine("Sending:" + message);

    }

    private void SendMessage(byte[] message, int len)

    {

        if (Client.Connected)

        {

            NetworkStream wclient = Client.GetStream();

            try

            {

                Console.WriteLine("Wysłalem:'" + Encoding.ASCII.GetString(message));

                wclient.Write(message, 0, len);

                wclient.Flush();

            }

            catch (Exception se)

            {

                Console.WriteLine("Błąd : " + se.Message);

            }


        }

    }

    public void run()

    {

        ReadSynchroHeader();

    }

}

Wiecie może jak to zoptymalizować?? :confused:

Z góry dzięki WIELKIE za pomoc:))

Pozdrawiam Northwest


(Gryph) #2

hej

debugowanie cos dalo?


(northwest) #3

nic nie daje :((


(system) #4

Mam pewne podejrzenia. Załóżmy że w jakimś momencie read_ptr=128 oraz write_ptr=128 i właśnie wpisujemy kolejne dane do bufora, wczyta się 128 bajtów (BUF_LEN-write_ptr) oraz write_ptr przeskoczy na 0, jeżeli przy tym bufor nie zostanie opróżniony, to dokona się kolejnego wczytania danych w ilości (read_ptr-write_ptr) czyli znowu 128, teraz read_ptr znowu jest równy write_ptr, czyli nie ma w buforze nic :smiley:

Wg mnie ilość bajtów do wczytania powinno się liczyć:

(BUF_LEN+read_ptr-write_ptr-1)%BUF_LEN

tak aby przy zapełnieniu bufora na całość ta ilość wychodziła równa 0 niezależnie od aktualnej wartości read_ptr. Chodzi o to że musisz zawszę trzymać przynajmniej jeden bajt bufora pustym, aby była jakaś różnica pomiędzy buforem całkowicie zapełnionym a pustym. Ponieważ operacja % nie należy do szybkich to proponuję pewne modyfikacje:

Zresztą wszystkie operacje typu X%BUF_LEN można będzie zastąpić na X&(BUF_LEN-1) a jeżeli zadeklarujesz const int BUF_MAX=BUF_LEN-1 to nawet na X&BUF_MAX zauważ że to znacznie szybsza operacja. Przypominam że takie zastąpienie jest poprawne jedynie kiedy BUF_LEN jest potęgą dwójki.

const int BUF_BITS=8;

const int BUF_LEN=1<
wtedy ilość do wczytania można obliczać jako:

code&(BUF_LEN-1)


(northwest) #5

dzięki :slight_smile: protestuję to, ale masz racje z tym dzieleniem :slight_smile: