2

I have tried to work around this as well as debug but I'm at a loose end here :( is there any alternative to using this to check for a client connection? This code works fine in a console application so i am guessing the thread is being blocked, although it may be something else i can't see?

public partial class Form1 : Form
{
    Socket s;

Declatation of socket.

private void startButton_Click(object sender, EventArgs e)
    {
        checkTimer.Enabled = true;
        if (bw.IsBusy != true)
        {
            bw.RunWorkerAsync();
        }
    }

Background thread to start on button press.

private void bw_DoWork(object sender, DoWorkEventArgs e)
{
        BackgroundWorker worker = sender as BackgroundWorker;

        working();
}

Thread runs the "working" method.

 private void working()
 {
     if (threadFirstRun == true)
     {
            threadFirstRun = false;
     }

        try
        {

            String tempAddr = tbAddr.Text;
            IPAddress ipAd = IPAddress.Parse("147.197.204.172");
            // use local m/c IP address, and 
            // use the same in the client
            String tempPort = tbPort.Text;
            /* Initializes the Listener */
            TcpListener myList = new TcpListener(ipAd, 3000);

            /* Start Listeneting at the specified port */
            myList.Start();
            tcConnection1 = "Console:\n" + "The server is running at port 3000...";
            tcConnection2 = "\n" + "The local End point is  :" + myList.LocalEndpoint;
            tcConnection3 = "\n" + "Waiting for a connection.....";

            while (true)
            {
                s = myList.AcceptSocket();
                if (s != null)
                {
                    if (connectionEstab == false)
                    {
                        tcEstab = "\n" + "Connection accepted from " + s.RemoteEndPoint;
                        connectionEstab = true;
                    }


                    byte[] b = new byte[100];
                    int k = s.Receive(b);
                    //Console.WriteLine("Recieved...");
                    for (int i = 0; i < k; i++)
                    {
                        //Console.Write(Convert.ToChar(b[i]));
                        tcValue = tcValue + Convert.ToString(b[i]);
                        valueArray[ii] = (float)Convert.ToDouble(b[i]);
                    }
                    tcValue = tcValue + "\n";
                    ii++;
                }
                else
                {
                    Thread.Sleep(200);
                }
            }

            ASCIIEncoding asen = new ASCIIEncoding();
            s.Send(asen.GetBytes("The string was recieved by the server."));
            rtbConsole.Text = rtbConsole.Text + "\n" + "Sent Acknowledgement";
            /* clean up */
            s.Close();
            myList.Stop();
        }
        catch (Exception ex)
        {
            tcError = "\n\n" + "Error..... " + ex.StackTrace;
        }
}

Working method starts the server and blocks upon calling myList.AcceptSocket();?

private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
        if ((e.Cancelled == true))
        {
            rtbConsole.Text = rtbConsole.Text + "\n" + "Canceled!";
        }

        else if (!(e.Error == null))
        {
            rtbConsole.Text = rtbConsole.Text + "\n\n" + ("Error: " + e.Error.Message);
        }

        else
        {
            rtbConsole.Text = rtbConsole.Text + "\n" + "Done!";
        }
}

private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
        rtbConsole.Text = rtbConsole.Text + "\n" + (e.ProgressPercentage.ToString() + "%");
}

private void stopButton_Click(object sender, EventArgs e)
{
        checkTimer.Enabled = false;
        if (bw.WorkerSupportsCancellation == true)
        {
            bw.CancelAsync();
        }
}

Other methods for some completeness.

Sending data from my android device is received by a console app running 1 thread, however nothing seems to happen in this windows form application upon sending data to the same ip and port from the same program on the same device. The separate thread just stays blocked and the android app cannot complete communication to send the data.

General Grievance
  • 4,555
  • 31
  • 31
  • 45
Sam
  • 350
  • 2
  • 9
  • http://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener.acceptsocket(v=vs.110).aspx see also http://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener.acceptsocketasync(v=vs.110).aspx – Tyler Jul 10 '14 at 15:31
  • It's supposed to block. The whole while cycle where you check `Pending` is a bad approach. Also, this would be much easier if you simply used the async methods with `await`. – Luaan Jul 10 '14 at 15:35
  • Edited the working method to remove the Pending check, didnt have that in the console app anyway. Haven't seen 'await' before I'll look it up. – Sam Jul 10 '14 at 15:48

2 Answers2

2

It's supposed to block. It can never return null. (Why is everybody doing this? It's like nobody on the web uses Accept correctly.)

Your problem is that after accepting one connection you process that connection and do nothing to resume accepting. The standard pattern is:

while (true) {
 var connectionSocket = listeningSocket.Accept();
 ProcessAsynchronously(connectionSocket);
}

Make sure ProcessAsynchronously returns immediately. Start a new Task or use async/await.

As you never exit the while loop you never get to sending data. Move all processing logic into ProcessAsynchronously.

usr
  • 168,620
  • 35
  • 240
  • 369
1

It is supposed to block. From MSDN:

AcceptSocket is a blocking method that returns a Socket that you can use to send and receive data. If you want to avoid blocking, use the Pending method to determine if connection requests are available in the incoming connection queue.

You can turn your whole implementation to use the async version: AcceptSocketAsync. Note this wont block your method, it will yield control back to the caller until a new Socket has been connected.

private async void bw_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker worker = sender as BackgroundWorker;
    await WorkingAsync();
}

And inside WorkingAsync:

private Task WorkingAsync
{
    // Do all other stuff,

    Socket socket = await myList.AcceptSocketAsync();

   // Do rest of stuff with the socket
}

I recommend you like at What is the async/await equivalent of a ThreadPool server? for a full implementation of an async tcp connection handler

Community
  • 1
  • 1
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • This has the same problem in that the program does not continue until a socket is available. – usr Jul 10 '14 at 16:07
  • There is no point in continuing his logic if a socket hasn't been received. Its either this or a `while (true)` which blocks, i think this version is preferable – Yuval Itzchakov Jul 10 '14 at 16:09
  • Ok, my comment does not make sense. Not sure why I said this. Anyway, this answer does not resolve his problem. – usr Jul 10 '14 at 16:11
  • I think he's got the pattern wrong. He executes the code in one background thread and makes it wait for a connection. The link i referred him to in my comment should provide a full non blocking implementation which can accept multiple clients at once. I just didn't want to copy and paste the whole solution. – Yuval Itzchakov Jul 10 '14 at 16:15