Καλώς ορίσατε στο dotNETZone.gr - Σύνδεση | Εγγραφή | Βοήθεια
σε

 

Αρχική σελίδα Ιστολόγια Συζητήσεις Εκθέσεις Φωτογραφιών Αρχειοθήκες

Windows Service που ακούει για UDP 514 port syslog messages

Îåêßíçóå áðü ôï ìÝëïò dtakis. Τελευταία δημοσίευση από το μέλος dtakis στις 13-10-2008, 11:21. Υπάρχουν 9 απαντήσεις.
Ταξινόμηση Δημοσιεύσεων: Προηγούμενο Επόμενο
  •  08-10-2008, 13:04 45259

    Windows Service που ακούει για UDP 514 port syslog messages

    Θέλω να φτιάξω ένα .Net Service σε C# που να ακούει την πόρτα 514 UDP για εισερχόμενα μηνύματα syslog από άλλο server.. O παρακάτω κώδικας υλοποιεί μέχρι το σημείο που λαμβάνεται η πληροφορία από το ανοιχτό socket...θα ήθελα παρατηρήσεις και σχόλιά σας καθώς το αναπτύσσω χωρίς ιδιαίτερη γνώση σε αυτό τον τομέα και δεν ξέρω αν κινούμαι σωστά

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Diagnostics;
    using System.Linq;
    using System.ServiceProcess;
    using System.Text;
    using System.Net.Sockets;
    using System.Net;

    namespace SyslogService
    {
    public partial class Service1 : ServiceBase
    {
    public Service1()
    {
    InitializeComponent();
    this.ServiceName = "SyslogServiceUDP514";
    this.CanStop = true;
    this.CanPauseAndContinue = true;
    this.AutoLog = true;
    }
    //public void Listen(int backlog );

    public static string GetStringFromSocket(Socket s)
    {
    Byte[] recBytes = new Byte[10001];
    int i = 0;
    string st = null;

    if (s.Available > 0)
    {
    i = s.Receive(recBytes, 0, s.Available, SocketFlags.None);
    char[] ac = Encoding.UTF8.GetChars(recBytes, 0, i);
    foreach (char c in ac)
    {
    st += c.ToString();
    }
    }
    return st;
    }


    protected override void OnStart(string[] args)
    {
    int port = 514;
    string SocketData = null;
    // create the socket
    Socket listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Udp);

    // bind the listening socket to the port
    IPAddress hostIP = (Dns.GetHostEntry(IPAddress.Any.ToString())).AddressList[0];
    IPEndPoint ep = new IPEndPoint(hostIP, port);
    listenSocket.Bind(ep);

    // start listening
    listenSocket.Listen(5000);//5000 maximum connections

    while (true) {

    try {
    SocketData = GetStringFromSocket(listenSocket.Accept());
    //listenSocket.Receive();
    }
    catch (Exception ex) {

    }
    }


    }

    protected override void OnStop()
    {
    }
    }
    }

    Δημοσίευση στην κατηγορία: , ,
  •  08-10-2008, 14:47 45261 σε απάντηση της 45259

    Απ: Windows Service που ακούει για UDP 514 port syslog messages

    Ο κώδικας έχει διάφορα θεματάκια. Καταρχήν, μπορείς να χρησιμοποιήσεις την κλάση UdpClient η οποία διευκολύνει τη λήψη και την αποστολή UDP datagrams. Ρίξε μία ματιά στο Using UDP Services για να δεις πόσο ευκολότερη είναι η χρήση της.  Δεύτερον, η GetStringFromSocket είναι κάπως περιττή. Μπορείς να μετατρέψεις ένα byte array απευθείας σε string με την GetString. Υποψιάζομαι επίσης ότι τα syslog datagrams δεν είναι κωδικοποιημένα σε UTF8 αλλά ASCII, οπότε αντί για UTF8 θα πρέπει να χρησιμοποιήσεις το Encoding.ASCII.GetString.

    Τέλος και ίσως το σημαντικότερο, χρησιμοποιείς busy waiting που σημαίνει ότι το service σου δεν σταματάει ποτέ να ακούει, ούτε καν για να ... το σταματήσεις από το control panel. Το κυρίως thread ενός service είναι αυτό το οποίο δέχεται τις εντολές start/stop από τα windows. Ρίξε μία ματιά στο documentation του UdpClient.BeginReceive για να δεις πως να ακούς ασύγχρονα για datagrams χωρίς να μπλοκάρεις το κυρίως thread του service σου.

    Άλλο ένα σημαντικό θέμα είναι ότι τα services δεν έχουν κάποιο UI οπότε δεν υπάρχει εύκολος τρόπος να σε ειδοποιήσουν ότι κάτι πάει στραβά. Θα πρέπει να βάλεις τον κατάλληλο κώδικα για logging και καταχωρήσεις σε Performance Counters για να ξέρεις τί συμβαίνει με το service, αν έσκασε κάτι, πόσα datagrams παίρνει το λεπτό κλπ.


    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  08-10-2008, 18:18 45273 σε απάντηση της 45261

    Απ: Windows Service που ακούει για UDP 514 port syslog messages

    Έχεις απόλυτο δίκιο..Διάβασα τα resources που έδωσες. Μάλλον χρειάζομαι ένα thread με καθυστέρηση που θα ακούει στην UDP πόρτα 514. Θα πρέπει να θυμηθώ πως γράφω Debug logs που ενργοποιούνται αναλόγως με τι build θα κάνω...αυτά αν θυμάμαι σωστά!

  •  09-10-2008, 15:52 45310 σε απάντηση της 45261

    Απ: Windows Service που ακούει για UDP 514 port syslog messages

    Ξανάγραψα το κομμάτι που αφορά το διάβασμα του socket αλλά χτυπάει μετά από μερικούς κύκλους:

     

    public static bool messageReceived=false;

    public static void ReceiveCallback(IAsyncResult ar)
    {
    UdpClient u = (UdpClient)((UdpState)(ar.AsyncState)).u;
    IPEndPoint e = (IPEndPoint)((UdpState)(ar.AsyncState)).e;

    Byte[] receiveBytes = u.EndReceive(ar, ref e);
    string receiveString = Encoding.ASCII.GetString(receiveBytes);
    LogMessageToFile(receiveString);

    //Console.WriteLine("Received: {0}", receiveString);
    messageReceived = true;


    }


    private static void StartListener()
    {
    // Receive a message and write it to the console.
    LogMessageToFile("ReceiveMessage");
    IPEndPoint e = new IPEndPoint(IPAddress.Any, listenPort);
    UdpClient u = new UdpClient(e);

    UdpState s = new UdpState();
    s.e = e;
    s.u = u;

    //Console.WriteLine("listening for messages");

    u.BeginReceive(new AsyncCallback(ReceiveCallback), s);

    // Do some work while we wait for a message. For this example,
    // we'll just sleep
    while (!messageReceived)
    {
    LogMessageToFile("Sleep 100 ms");
    Thread.Sleep(100);
    }

    }

    protected override void OnStart(string[] args)
    {
    LogMessageToFile("Service Started");
    //StartListener();
    ThreadStart job = new ThreadStart(StartListener);
    Thread thread = new Thread(job);
    thread.Start();
    LogMessageToFile("Thread Started");
    }

    protected override void OnStop()
    {


    if ((Thread.CurrentThread != null) && (Thread.CurrentThread.IsAlive))
    {
    Thread.Sleep(5000);
    Thread.CurrentThread.Abort();

    LogMessageToFile("Service Stopped");

    }



    }

    Το exception χτυπάει στο

    UdpClient u = new UdpClient(e);

    Παραθέτω το $exception {"Only one usage of each socket address (protocol/network address/port) is normally permitted"} System.Exception {System.Net.Sockets.SocketException}

    Δηλαδή ανοίγοντας το thread ανοίγω κάθε φορά και νέο UdpClient;


  •  09-10-2008, 16:52 45311 σε απάντηση της 45259

    Απ: Windows Service που ακούει για UDP 514 port syslog messages

    Επίσης παρατήρησα ότι δεν εκτελεί ποτέ (χρήση χωρίς thread) τη γραμμή

    UdpClient u = new UdpClient(e);

    και υποθέτω ότι έχει σχέση με την παρακάτω δήλωση κλάσης που αναγκάστηκα να περάσω καθώς δεν δούλευε στο παράδειγμα που είχε το msdn! 

     class UdpState
    {
    public UdpClient u;
    public IPEndPoint e;
    }

  •  09-10-2008, 17:47 45312 σε απάντηση της 45311

    Απ: Windows Service που ακούει για UDP 514 port syslog messages

    Λάθος μου, έτρεχα και 2ο εργαλείο που άκουγε στην πόρτα 514 με αποτέλεσμα να μην μπορεί να ανοιχτεί νέος listener!

  •  09-10-2008, 21:10 45324 σε απάντηση της 45311

    Απ: Windows Service που ακούει για UDP 514 port syslog messages

    Ω τους $)@(&(@(*@$~!

    Δεν ξέρω αν εσύ τους βαθμολόγησες με 1 αστεράκι, αλλά πήγα κι εγώ και τράβηξα άλλο ένα. Και μάλιστα, το sample σε C++ αντί για u,e, έχει κανονικά ονόματα στα fields ipEndPoint,udpClient. Προφανώς κάποιος έκανε τσαπατσοδουλιά και απλώς αντέγραψε ένα κομμάτι κώδικα από άλλο sample!

    Ψάχνοντας για UdpState στο MSDN βρήκα αρκετά posts από κόσμο που μπερδεύτηκε από αυτό το sample. Ντροπή!


    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  10-10-2008, 17:47 45354 σε απάντηση της 45324

    Απ: Windows Service που ακούει για UDP 514 port syslog messages

    Κάπου κάπου συμβαίνουν και αυτά...

    Ο μέχρι τώρα κώδικας:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Diagnostics;
    //using System.Linq;
    using System.ServiceProcess;
    using System.Text;
    using System.Net.Sockets;
    using System.Net;
    using MySql.Data;
    using MySql.Data.MySqlClient;
    using System.Threading;
    using System.IO;

    namespace SyslogService2005
    {
    public partial class Service1 : ServiceBase
    {
    public Service1()
    {
    InitializeComponent();
    this.ServiceName = "SyslogServiceUDP514";
    this.CanStop = true;
    this.CanPauseAndContinue = true;
    this.AutoLog = true;
    }

    private const int listenPort = 514;

    class UdpState
    {
    public UdpClient u;
    public IPEndPoint e;
    }


    public static bool messageReceived = false;

    public static bool processWorking = false;

    public static void ReceiveCallback(IAsyncResult ar)
    {
    UdpClient u = (UdpClient)((UdpState)(ar.AsyncState)).u;
    IPEndPoint e = (IPEndPoint)((UdpState)(ar.AsyncState)).e;


    Byte[] receiveBytes = u.EndReceive(ar, ref e);
    string receiveString = Encoding.ASCII.GetString(receiveBytes);
    LogMessageToFile(receiveString);

    //Console.WriteLine("Received: {0}", receiveString);
    messageReceived = true;


    }



    private static void StartListener()
    {
    // Receive a message and write it to the console.
    //LogMessageToFile("ReceiveMessage");

    IPEndPoint e = new IPEndPoint(IPAddress.Any, listenPort);
    //LogMessageToFile("UdpClient");
    UdpClient u = new UdpClient(e);
    //LogMessageToFile("UdpState");
    UdpState s = new UdpState();
    //LogMessageToFile("s.e = e");
    s.e = e;
    // LogMessageToFile("s.u");
    s.u = u;


    //Console.WriteLine("listening for messages");

    //LogMessageToFile("Start Asychronous");
    while (processWorking==true)
    {
    u.BeginReceive(new AsyncCallback(ReceiveCallback), s);

    // Do some work while we wait for a message. For this example,
    // we'll just sleep
    while (!messageReceived)
    {
    //LogMessageToFile("Sleep 100 ms");
    Thread.Sleep(100);
    }
    }



    }


    static void LogMessageToFile(string msg)
    {
    System.IO.StreamWriter sw = System.IO.File.AppendText("C:\\Services\\LogFile.txt");
    try
    {
    string logLine = System.String.Format("{0:G}: {1}.", System.DateTime.Now, msg);
    sw.WriteLine("+----------------------------------------------------------------+");

    sw.WriteLine(logLine);
    }
    finally
    {
    sw.Close();
    }
    }

    protected override void OnStart(string[] args)
    {
    // TODO: Add code here to start your service.
    //LogMessageToFile("Service Started");

    processWorking = true;

    //StartListener();
    //ThreadStart job = new ThreadStart(StartListener);
    //Thread thread = new Thread(job);
    //thread.Start();
    //LogMessageToFile("StartListener Started");
    StartListener();
    }

    protected override void OnStop()
    {
    // TODO: Add code here to perform any tear-down necessary to stop your service.
    if ((Thread.CurrentThread != null) && (Thread.CurrentThread.IsAlive))
    {
    processWorking = false;
    Thread.Sleep(5000);
    Thread.CurrentThread.Abort();

    LogMessageToFile("Service Stopped");

    }
    }
    }
    }

    Δεν έχω ακόμα πιάσει πως δουλεύει ακριβώς ένα service γιατί δουλεύει μέχρι να βγει το μνμ:

    ---------------------------
    Services
    ---------------------------
    The SyslogService2005 service on Local Computer started and then stopped. Some services stop automatically if they are not in use by other services or programs.
    ---------------------------
    OK  
    ---------------------------

    Το περέργο είναι ότι γράφει στο αρχείο τα μνμτα και μετά βγαίνει το μνμ!

  •  12-10-2008, 15:46 45398 σε απάντηση της 45354

    Απ: Windows Service που ακούει για UDP 514 port syslog messages

    Λύθηκε και αυτό το πρόβλημα με την παρακάτω αλλαγή στην επανάληψη του listening:

    while (processWorking == true)
    {
    u.BeginReceive(new AsyncCallback(ReceiveCallback), s);

    Thread.Sleep(100);
    }

    αλλά ακόμα ως windows service ΔΕΝ ξεκινάει σωστά!

    Δηλαδή εκκινεί η λειτουργία κανονικά και τρέχει εκτελόντας ότι θέλω αλλά ο service manager περιμένει για ένα διάστημα και μετά αποκρίνεται ότι το service didn't respond in a timely fashion!

    Καμία ιδέα; Εδώ λογικά έχει σχέση με το πως έγραψα το service αλλά από τα παραδείγματα που βλέπω δεν παρατηρώ καμία άλλη επιλογή...ειδικά σε αυτά που γράφουν ένα Event στο Eventlog στο OnStart και ένα Event ότι τερματίσανε το service στο OnStop...

  •  13-10-2008, 11:21 45422 σε απάντηση της 45398

    Απ: Windows Service που ακούει για UDP 514 port syslog messages

    Το ωραίο είναι ότι ως service χτυπάει exception γιατί πάνε να γράψουν στο log πάνω από δύο εργασίες .... ενώ η έκδοση που έχω φτιάξει να τρέχει ως console application συνεχίζει χωρίς προβλήματα...(και γράφει στο log)

Προβολή Τροφοδοσίας RSS με μορφή XML
Με χρήση του Community Server (Commercial Edition), από την Telligent Systems