user3884423
user3884423

Reputation: 594

TCPClient will only ever connect once

I am building an app that communicates to a machine via TCP. The issue I have is that I can connect and all is well but once I disconnect and then try and reconnect all I get is error

The code I have in the form is

   private void btn_connect_Click(object sender, EventArgs e)
    {
        try
        {

            Log(LogMsgType.Normal, String.Format("Connected on {0}\n", DateTime.Now));

            string ip = (txt_ipadd_1.Text + "." + txt_ipadd_2.Text + "." + txt_ipadd_3.Text + "." + txt_ipadd_4.Text);

            Log(LogMsgType.Normal, String.Format("Connecting to IP address " + ip + "   Port # " + txt_port.Text +"\n"));

            string con = Codenet.Connect_TCP(ip, Convert.ToInt32(txt_port.Text)); //connect to this one

            Log(LogMsgType.Normal, String.Format(con + "\n"));

            toolStripStatusLabel1.Text = "Connected";

            btn_connect.Visible = false;
            btn_disconnect.Visible = true;
            ip = "";


        }

        catch (Exception d)
        {
            Log(LogMsgType.Error, String.Format("Error..... " + d.StackTrace +"\n"));
        }
    }

Which goes over to code from the Codenet dll which does the connection and disconnection

     public static string Connect_TCP(string ip, int Port)
    {
            tcpclnt.Connect(ip, Port); 
            connection_type = "TCP";
            return "Connected OK ";
    }

    public static void DisConnect_TCP()
    {
        tcpclnt.GetStream().Close();   
        tcpclnt.Close();
    }

The error I get is:

Error..... at System.Net.Sockets.TcpClient.Connect(String hostname, Int32 port) at
comms_engine.Codenet.Connect_TCP(String ip, Int32 Port) in C:\a\code\g_com_test_1\comms_engine\Codenet.cs:line 37 at
comms_test.CommTester.btn_connect_Click(Object sender, EventArgs e) in C:\a\code\g_com_test_1\dll_test\ethernet.cs:line 98

It will not perform the tcpclnt.Connect(ip, Port) even if the ip is different. It seems that something is still open but what I do not know as the machine has disconnected. I know that as I have UDP in it sending out how many connections it has and I can see then increase and decrease OK.

I tried "public string Connect_TCP(string ip, int Port)" and making a NEW instance of the dll befor calling the connect from the form but that did not work either.

Any ideas what I am doing wrong.

Thanks for answers so far but still I have an issue. I read the MSDN and made a test app and I can now see what is wrong but am clueless on how to fix it at the moment. I am declaring the Client as Static global so I can get it from the connect and disconnect button. I think thta this always creates new instances and I never close them. First time round the machine tells me it has diconnected bu t the app never reconnects In debug mode it falls over at client.Connect(ipEndPoint); with "InvalidOperationException was unhandled" followed by "Once the socket has been disconnected, you can only reconnect again asynchronously, and only to a different EndPoint. BeginConnect must be called on a thread that won't exit until the operation has been completed."

I guess I need to put this Client inside the btn_connect_click and get a pointer to it from inside the disconnect but how?

The full code is

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.IO;
using System.IO.Ports;
using System.Diagnostics;
using System.Threading;

namespace TCP_Test
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        static  Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        private void btn_connect_Click(object sender, EventArgs e)
        {

            string ip = (txt_ipadd_1.Text + "." + txt_ipadd_2.Text + "." + txt_ipadd_3.Text + "." + txt_ipadd_4.Text);

            IPHostEntry ipHost = Dns.GetHostEntry(Dns.GetHostName());
            IPAddress ipAddr = IPAddress.Parse(ip);
            IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, Convert.ToInt32(txt_port.Text));

            // Connect the socket to the remote end point.
            client.Connect(ipEndPoint);

            rchTxtBx_output.AppendText("connected to " + ipEndPoint + "\n\r");
          }

          private void btn_disconnect_Click(object sender, EventArgs e)
          {
            client.Shutdown(SocketShutdown.Both);

            client.Disconnect(true);
            if (client.Connected)
                rchTxtBx_output.AppendText("We're still connnected \n\r");
            else
                rchTxtBx_output.AppendText("We're disconnected \n\r");

           }




    }


} 

Upvotes: 3

Views: 4910

Answers (3)

user3884423
user3884423

Reputation: 594

Thanks for the help I have now solved it. See above for full code but below is teh snippet that makes it work. Just add client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); inside the connect button. My testing now shows it connects and disconnects and allows reconnect or connect to anothe machine. Only took me two man days to work that out with your help.

static  Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);



    private void btn_connect_Click(object sender, EventArgs e)
    {
        if (client.Connected)
        {
            client.Shutdown(SocketShutdown.Both);

            client.Disconnect(true);
            client.Close();
        }
        else
        {
            client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                string ip = (txt_ipadd_1.Text + "." + txt_ipadd_2.Text + "." + txt_ipadd_3.Text + "." + txt_ipadd_4.Text);

                IPHostEntry ipHost = Dns.GetHostEntry(Dns.GetHostName());

Upvotes: 5

dvasanth
dvasanth

Reputation: 1377

When the connection is closed, underlying socket(TCPClient.Client returns socket) needs to be set for reuse . Use the Socket.Disconnect(true) instead of close to reconnect on the socket. Check the link: http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.disconnect(v=vs.90).aspx

Upvotes: 1

Remy Lebeau
Remy Lebeau

Reputation: 596332

Once you disconnect a TCP socket, it cannot be reconnected. You have to release the socket and create a new one. This is not just limited to the .NET TCPClient class, this is how all socket APIs work in general (WinSock, BSD, etc).

The exception to this rule is the WinSock2-specific DisconnectEx() function, which has a TF_REUSE_SOCKET flag that allows ConnectEx() (and AcceptEx()) to re-use an existing SOCKET instead of requiring a new socket to be created. But that does not apply in your situation.

In the majority of cases, once you disconnect a socket, you have to create a new socket from scratch.

Upvotes: 5

Related Questions