C# tcp listener multithreading / multiple connections


Hace un tiempo “el negro” me había pedido el tcp listener modo consola… ahora necesitaba una mejora para que acepte multiples conecciones, dado que el anterior, solo aceptaba una.
No pude encontrar nada concreto que funcionara en la web, asi que me tuve que poner a hacer el trabajo pesado: un rejunte de código para obtener un tcp listener multithreading.
El resultado es este:

Program.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace tcplistener_console
{
    class Program
    {
        static int Main(string[] args)
        {
            Console.Write(“tcplistener by hvivani – 20110225 – para el negro: \r\n”);
            if (args.Length == 0)
            {
                System.Console.WriteLine(“Parametros: Puerto IP   \r\n”);
                System.Console.WriteLine(“Ejemplo: tcplistener 2525 127.0.0.1  \r\n”);
                System.Console.WriteLine(“si tenes mas de una interfaz de red, usa la ip de dicha interfaz.  \r\n”);
                return 1;
            }
            else
            {
                multicnnNew.iniciar(args[0], args[1]);
                return 0;
            }

        } 
    }
}


multicnnNew.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace tcplistener_console
{
    public class multicnnNew
    {
        // Thread signal.
        public static ManualResetEvent clientConnected = new ManualResetEvent(false);

        public static void iniciar(string puerto, string addr)
        {
            IPAddress localAddr = IPAddress.Parse(addr);
            TcpListener server = new TcpListener(localAddr, int.Parse(puerto));
            server.Start();

            server.BeginAcceptTcpClient(AcceptCallback, server);
            clientConnected.WaitOne();
        }

        private static void AcceptCallback(IAsyncResult ar)
        {
            TcpListener server = (TcpListener)ar.AsyncState;
            ClientState state = new ClientState();

            // Once the accept operation completes, this callback will
            // be called.  In it, you can create a new TcpClient in much
            // the same way you did it in the synchronous code you had:

            state.client = server.EndAcceptTcpClient(ar);

            // We’re going to start reading from the client’s stream, and
            // we need a buffer for that:

            state.buffer = new byte[4096];

            // Note that the TcpClient and the byte[] are both put into
            // this “ClientState” object.  We’re going to need an easy
            // way to get at those values in the callback for the read
            // operation.

            // Next, start a new accept operation so that we can process
            // another client connection:

            server.BeginAcceptTcpClient(AcceptCallback, server);

            // Finally, start a read operation on the client we just
            // accepted.  Note that you could do this before starting the
            // accept operation; the order isn’t really important.

            state.client.GetStream().BeginRead(state.buffer, 0, state.buffer.Length, ReadCallback, state);
        }

        private static void ReadCallback(IAsyncResult ar)
        {
            ClientState state = (ClientState)ar.AsyncState;
            int cbRead = state.client.GetStream().EndRead(ar);

            if (cbRead == 0)
            {
                // The client has closed the connection
                return;
            }
            //else
            //{
                //Console.WriteLine(“hay datos”);
            //}

            // Your data is in state.buffer, and there are cbRead
            // bytes to process in the buffer.  This number may be
            // anywhere from 1 up to the length of the buffer.
            // The i/o completes when there is _any_ data to be read,
            // not necessarily when the buffer is full.

            // So, for example:

            string strData = Encoding.ASCII.GetString(state.buffer, 0, cbRead);
            Console.WriteLine(strData);

            // For ASCII you won’t have to worry about partial characters
            // but for pretty much any other common encoding you’ll have to
            // deal with that possibility, as there’s no guarantee that an
            // entire character will be transmitted in one piece.

            // Of course, even with ASCII, you need to watch your string
            // terminations.  You’ll have to either check the read buffer
            // directly for a null terminator, or have some other means
            // of detecting the actual end of a string.  By the time the
            // string goes through the decoding process, you’ll have lost
            // that information.

            // As with the accept operation, we need to start a new read
            // operation on this client, so that we can process the next
            // bit of data that’s sent:

            state.client.GetStream().BeginRead(state.buffer, 0, state.buffer.Length, ReadCallback, state);
        }
    }
}

ClientState.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;

namespace tcplistener_console
{
    public class ClientState
    {
        public TcpClient client;
        public byte[] buffer;
    }
}

Estas son las clases necesarias para crear un proyecto en modo consola.
y, como diría “el negro”: 
SALUTE !

Anuncios

Acerca de hvivani

sysadmin, developer, RHCSA
Esta entrada fue publicada en Uncategorized y etiquetada . Guarda el enlace permanente.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s