0

I'm trying to make my code accept two or more clients to my server program. Here is the code. I need help with the code on how to accept multiple clients at the same time. I got an error with the port. It says "Only one usage of each socket address (protocol/network address/port) is normally permitted"

namespace TCPServer { public partial class Form1 : Form {

    //Create TCP/IP Socket 
    Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

    TcpListener mTCPListener;
    TcpClient mTCPClient = new TcpClient();
    NetworkStream serverStream;

    byte[] mRx;

    public Form1()
    {
        InitializeComponent();
    }

    void onCompleteAcceptTcpClient(IAsyncResult iar)
    {
        TcpListener tcpl = (TcpListener)iar.AsyncState;
        try
        {
            ThreadStart delegateR = new ThreadStart(() => 
            mTCPClient = tcpl.EndAcceptTcpClient(iar));

            Thread R = new Thread(delegateR);
            R.Start();
            printLine("Client Connected...");

            //Begin Asynchronous Read
            mRx = new byte[1024];
            mTCPClient.GetStream().BeginRead(mRx, 0, mRx.Length, onCompleteReadFromTCPClientStream, mTCPClient);

        }
        catch (Exception exc)
        {
            MessageBox.Show(exc.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }

    private void btnStartListening_Click_1(object sender, EventArgs e)
    {
        try
        {
            IPAddress ipaddr;
            int nPort = 23000;

            #region Validating IP Address
            //if (!int.TryParse(tbPort.Text, out nPort))
            //{
            //    nPort = 23000;
            //}
            if (!IPAddress.TryParse(tbIPAddress.Text, out ipaddr))
            {
                MessageBox.Show("Invalid IP address supplied.");
                return;
            }
            #endregion




                mTCPListener = new TcpListener(ipaddr, nPort);
                //Start Listening
                mTCPListener.Start();

                //ThreadStart delegateT = new ThreadStart(() => { RefreshLot(lotId); });
                //Thread T = new Thread(delegateT);
                //T.Start();
                ThreadStart delegateT = new ThreadStart(() => mTCPListener.BeginAcceptTcpClient(onCompleteAcceptTcpClient, mTCPListener));
                Thread T = new Thread(delegateT);
                T.Start();
                //Begin accept tcp client (only one)
                //mTCPListener.BeginAcceptTcpClient(onCompleteAcceptTcpClient, mTCPListener));
                if (mTCPListener.Pending())
                {
                    nPort = nPort + 1;
                    mTCPListener.BeginAcceptTcpClient(onCompleteAcceptTcpClient, mTCPListener);
                }

        }
        catch (Exception ex)
        {
            throw ex;
        }
    }


    void onCompleteReadFromTCPClientStream(IAsyncResult iar)
    {
        TcpClient tcpc;
        int nCountReadBytes = 0;
        string strRecv;
        try
        {
            tcpc = (TcpClient)iar.AsyncState;
            nCountReadBytes = tcpc.GetStream().EndRead(iar);

            if (nCountReadBytes == 0)
            {
                MessageBox.Show("Client disconnected.");
                return;
            }

            strRecv = Encoding.ASCII.GetString(mRx, 0, nCountReadBytes);
            printLine(strRecv);
            mRx = new byte[1024];
            tcpc.GetStream().BeginRead(mRx, 0, mRx.Length, onCompleteReadFromTCPClientStream, tcpc);
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }

    public void printLine(string _strPrint)
    {
        tbConsoleOutput.Invoke(new Action<string>(doInvoke), _strPrint);
    }

    public void doInvoke(string _strPrint)
    {
        tbConsoleOutput.Text = _strPrint + Environment.NewLine + tbConsoleOutput.Text;
    }

    private void onCompleteWriteToClientStream(IAsyncResult iar)
    {
        try
        {
            TcpClient tcpc = (TcpClient)iar.AsyncState;
            tcpc.GetStream().EndWrite(iar);
        }
        catch (Exception exc)
        {
            MessageBox.Show(exc.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }

    private void btnSend_Click_1(object sender, EventArgs e)
    {
        byte[] tx = new byte[1024];
        if (string.IsNullOrEmpty(tbPayload.Text)) return;

        try
        {
            if (mTCPClient != null)
            {
                if (mTCPClient.Client.Connected)
                {

                    //This is the message that will be sent
                    tx = Encoding.ASCII.GetBytes("Server MESRII sent: " + tbPayload.Text + "  " + DateTime.Now);
                    mTCPClient.GetStream().BeginWrite(tx, 0, tx.Length, onCompleteWriteToClientStream, mTCPClient);
                }
            }
        }
        catch (Exception exc)
        {
            MessageBox.Show(exc.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }

    private void btnStartListening2_Click(object sender, EventArgs e)
    {

    }


}
Christian
  • 11
  • 3
  • 1
    What was issue with answer from my answer to previous posting : https://stackoverflow.com/questions/47799387/c-sharp-how-to-accept-multiple-clients-in-one-tcp-server I said on my 1st comment you cannot have two connections from same IP address with same port number. If you want to test from same IP then you need two port numbers. So create two Listeners with two different port numbers. Have both Listeners use same Accept Event. After testing you can eliminate 2nd listener. It is common with connections for a client to try multiple port numbers and multiple servers on large networks. – jdweng Dec 14 '17 at 00:52
  • how can I assign different port numbers "let's say dynamically"? If instead of two clients, get another one... – Christian Dec 14 '17 at 00:59
  • Server ports number are never assigned dynamically. They are always preassigned to one port number or a range of port numbers. At client side you either check to make sure another app isn't using same port number to same server, or attempt a connection on one port number and if it fails try next port number in the range. With TCP you can have only one connections with the same three parameters 1) Source IP address 2) Destination IP address 3) Port number. – jdweng Dec 14 '17 at 09:53

2 Answers2

0

You should create single TcpListener on your server, besause only one listener can use one port. When you getting new connection (AcceptTcpClient method), you may begin new thread for messaging exchange with client. You can see good examples in this question

Anton Gorbunov
  • 1,414
  • 3
  • 16
  • 24
  • Beginning a new thread is an extremely bad practice. You should use async API for it. Beginning a new thread for each client may be ok for small servers, but will eventually cause a crash at some point on servers which have many clients connected. – Nicolas Iceberg Dec 01 '20 at 16:39
0

I was working in the code and took all the suggestions provided. What I did was Call the Start listening this way...

`private void btnStartListening_Click_1(object sender, EventArgs e) { try { index++;

            IPAddress ipaddr = IPAddress.Any;
            int x = Convert.ToInt32(tbPort.Text);
            int nPort = x;


            //#region Validating IP Address
            //if (!int.TryParse(tbPort.Text, out nPort))
            //{
            //    nPort = 23000;
            //}
            //if (!IPAddress.TryParse(tbIPAddress.Text, out ipaddr))
            //{
            //    MessageBox.Show("Invalid IP address supplied.");
            //    return;
            //}
            //#endregion

            if (nPort >= 23000)
            {
                nPort = nPort + 1;
                mTCPListener = new TcpListener(ipaddr, nPort);

                //Start Listening on port nPort + 1
                mTCPListener.Start();
                testingThreadStart.Add(new ThreadStart(() => mTCPListener.BeginAcceptTcpClient(onCompleteAcceptTcpClient, mTCPListener)));
                //ThreadStart delegateT = new ThreadStart(() => mTCPListener.BeginAcceptTcpClient(onCompleteAcceptTcpClient, mTCPListener));
                testingThread.Add(new Thread(testingThreadStart[index]));
                //Thread T = new Thread(delegateT);
                //T.Start();
                testingThread[index].Start();
                //Begin accept tcp client (only one)
                //mTCPListener.BeginAcceptTcpClient(onCompleteAcceptTcpClient, mTCPListener));
            }
            else
            {
                mTCPListener = new TcpListener(ipaddr, nPort + 1);

                //Start Listening on port 23000
                mTCPListener.Start();

                ThreadStart delegateT = new ThreadStart(() => mTCPListener.BeginAcceptTcpClient(onCompleteAcceptTcpClient, mTCPListener));
                Thread T = new Thread(delegateT);
                T.Start();

            }
        }`

Also added list of threads on the beginning of the code...

 List<ThreadStart> testingThreadStart = new List<ThreadStart>();
    List<Thread> testingThread = new List<Thread>();

and thats how it worked. If anyone need/want the complete code, I can post it. For future examples.

Christian
  • 11
  • 3