views:

43

answers:

3

I have around 5000 modem (thin clients), and I want to communicate with them, one of a my method is like this : string GetModemData(modemID), now I have an open port in server that listens to modem and I'm using socket programming to send data to modems (calling related function), but when i want send data to multiple modem in a same time and get response from them, I don't know what should i do? I can send data to one modem and waiting for its response and then send another data to other modems (sequential), but the problem is client should be wait long time to get answer(may be some different client want to get some information from modems so they all will be wait into the Q or something like this), I think one way to solving this problem is to use multiple port and listen for each modem to related port, but it takes too many ports and also may be memory usage going up and exceed my available memory space, so some lost may be occurred (is this true?). what should to do ? I'd thinking about Parallelism, but i think its not related i should to wait for one port, because i don't know should to pass current received data to which client. I'm using asp.net.

currently I'm doing like this:

private void StartListener()
    {
        ModemTcpListener = new TcpListener(ModemPort);
        //ClientTcpListener = new TcpListener(ClientPort);

        ModemTcpListener.Start();
        ModemTcpListener.BeginAcceptTcpClient(new AsyncCallback(DoAcceptModemCallback), ModemTcpListener);
    }

and in return

private void DoReadModemCallback(IAsyncResult ar)
         {
             try
             {
                 bool bRet = ar.AsyncWaitHandle.WaitOne(420000);
                 Modem modem = ar.AsyncState as Modem;
                 if (!bRet || modem == null)
                 {
                     return;
                 }
           }
           catch{}
            // now send data to which client?????? if i'm going to use async????
}

and :

private void DoAcceptModemCallback(IAsyncResult ar)
        {
            try
            {
                ModemTcpListener.BeginAcceptTcpClient(new AsyncCallback(DoAcceptModemCallback), ModemTcpListener);
                TcpClient tcpClient = ModemTcpListener.EndAcceptTcpClient(ar);
                Modem modem= new Modem(tcpClient, "");
                tcpClient.GetStream().BeginRead(modem.Buffer, 0, tcpClient.ReceiveBufferSize, new AsyncCallback(DoReadModemCallback), modem);
                ModemTcpListener.BeginAcceptTcpClient(new AsyncCallback(DoAcceptModemCallback), ModemTcpListener);
                Log.Write("a Modem connect ...");
            }
            catch (Exception ex) 
            {
            }
        }
A: 

You need to use the asynchronous tcp/ip methods. This article shows how:

http://www.codeproject.com/KB/IP/asyncsockets.aspx

The critical piece is the BeginReceive() and related callback functions. Any more q's, please leave comments to this answer ;) BEST OF LUCK!

vdoogs
Further, I would suggest you keep an array of open connections, for example Socket [] = new Socket[5000]; If you use the asynchronous calls port usage and memory should not be a problem, as the processing will only happen on open connection, begin receiving, and when data is received (function callback).
vdoogs
That article contains several flaws that can make the application crash or behave unexpected. It might work OK with one or two connected sockets. Never mix threads and asynchronous method as he do in the article. And never check an event for null and then invoke it, the event may have been cleared in between. Do not eat exceptions with empty catch blocks.
jgauffin
@jgauffin, I agree with you, but vdoogs openning too many socket does not solve my problem, I should listen too which modem in which socket? may be I can't say carefully my problem please see my comment on A_Nablsi.
SaeedAlg
+1  A: 

You need multi threading, whenever a client establishes a connection to the server start a new thread for it and start communication send/receive.

Here are some articles explaining multithreading in c#, c-sharpcorner codeproject

And here's a sample server application with multithreading, http://www.dotnetspider.com/resources/2829-A-multi-readed-server-C-which-finds-prime-num.aspx

A_Nablsi
think about this scenario: you have 5 different clients, they want to fetch 5 different thin clients data, if they listen on a single port how i can find witch data received for witch client to pass it? if i where connecting to clients with tcp ip or like this i can save their ip address (MAC or ...) and send back data to them, but I'm using asp.net just some function call and i don't know send received data to which client. because I'm not a master IIS will be do it.
SaeedAlg
I would not create a new thread for every client, it's a very inefficient way. Use asynchronous IO instead (BeginRead/EndRead etc).
jgauffin
Please I need more explanation I am unable to imagine how do you keep the connections with the clients at the server and I am not sure if you are establishing a connection from the server to the clients when you want to get their data. Your application as I imagine whenever a clients establish a connection to the server has to keep a reference to the client's socket object and by this you can communicate with all the clients you keep references of their socket objects asychnronously or by multithreading.
A_Nablsi
@A_Nablsi, thanks, but main problem is i have 2 different kind of clients: WebClient ----> request server ------> server -------> request thin clients, and now thin clients will be send data server now server should find to send data to related client, problem is this, I can't determine server send received data to which client because its just a function call from iis and server will be responded the calls by some priority which may be different from related response order of thin clients.
SaeedAlg
@A_Nablsi, I just updated the question
SaeedAlg
+2  A: 

Heres an example keeping track of all your clients. I've compacted it for readability. You should really split it up into multiple classes.

I'm using Pool (which I just created and commited) and SimpleServer. Both classes are part of a library that I'm currently building (but far from done).

Don't be afraid of having 5000 sockets open, they do not consume much resources when you are using asynchronous operations.

    public class SuperServer
    {
        private List<ClientContext> _clients = new List<ClientContext>();
        private SimpleServer _server;
        private Pool<byte[]> _bufferPool;

        public SuperServer()
        {
            // Create a buffer pool to be able to reuse buffers
            // since your clients will most likely connect and disconnect
            // often.
            //
            // The pool takes a anonymous function which should return a new buffer.
            _bufferPool = new Pool<byte[]>(() => new byte[65535]);
        }

        public void Start(IPEndPoint listenAddress)
        {
            _server = new SimpleServer(listenAddress, OnAcceptedSocket);

            // Allow five connections to be queued (to be accepted)
            _server.Start(5); 
        }

        // you should handle exceptions for the BeginSend
        // and remove the client accordingly.
        public void SendToAll(byte[] info)
        {
            lock (_clients)
            {
                foreach (var client in _clients)
                    client.Socket.BeginSend(info, 0, info.Length, SocketFlags.None, null, null);
            }
        }

        // Server have accepted a new client.
        private void OnAcceptedSocket(Socket socket)
        {
            var context = new ClientContext();
            context.Inbuffer = _bufferPool.Dequeue();
            context.Socket = socket;

            lock (_clients)
                _clients.Add(context);

            // this method will eat very few resources and
            // there should be no problem having 5000 waiting sockets.
            context.Socket.BeginReceive(context.Inbuffer, 0, context.Inbuffer.Length, SocketFlags.None, OnRead,
                                        context);
        }

        //Woho! You have received data from one of the clients.
        private void OnRead(IAsyncResult ar)
        {
            var context = (ClientContext) ar.AsyncState;
            try
            {
                var bytesRead = context.Socket.EndReceive(ar);
                if (bytesRead == 0)
                {
                    HandleClientDisconnection(context);
                    return;
                }

                // process context.Inbuffer here.
            }
            catch (Exception err)
            {
                //log exception here.
                HandleClientDisconnection(context);
                return;
            }

            // use a new try/catch to make sure that we start
            // read again event if processing of last bytes failed.
            try
            {
                context.Socket.BeginReceive(context.Inbuffer, 0, context.Inbuffer.Length, SocketFlags.None, OnRead,
                                            context);
            }
            catch (Exception err)
            {
                //log exception here.
                HandleClientDisconnection(context);
            }
        }

        // A client have disconnected.
        private void HandleClientDisconnection(ClientContext context)
        {
            _bufferPool.Enqueue(context.Inbuffer);
            try
            {
                context.Socket.Close();
                lock (_clients)
                    _clients.Remove(context);
            }
            catch(Exception err)
            {
                //log exception
            }
        }


        // One of your modems
        // add your own state info.
        private class ClientContext
        {
            public byte[] Inbuffer;
            public Socket Socket;
        }

    }

Used classes:

jgauffin
thanks i will see them, now i'm going to sleep:D
SaeedAlg
I'd accept your answer because of your help :D
SaeedAlg