Main Site Documentation

How to close and open TCP connections properly


#1

hi, i’m trying to establish a connection with a device via TCP/IP send some data and also recieve data, then close the connection.
After that, it would be able to connect with another device and do the same things.

Here is my code.


//global variables
static Socket ServidorTCPIP;
static IPEndPoint TCPEndpoint;

Here i make the connection and send the data, also start a thread for the incoming one.


ServidorTCPIP = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
TCPEndpoint = new IPEndPoint(IPAddress.Parse("192.168.1.103"), 23);
ServidorTCPIP.Connect(TCPEndpoint);
new Thread(LecturaTCP).Start();
ServidorTCPIP.Send(Encoding.UTF8.GetBytes("hello world\r\n"));

here the thread code


        private void LecturaTCP()
        {
            while (true)
            {
                if (ServidorTCPIP.Poll(-1, SelectMode.SelectRead))
                {
                    byte[] entrada = new byte[ServidorTCPIP.Available];
                    int cuenta = ServidorTCPIP.Receive(entrada);
                    char[] caracteres = Encoding.UTF8.GetChars(entrada);
                    string cadena = new string(caracteres, 0, cuenta);
                    respuesta = cadena;
                }
            }
        }

All this works well but i’m having an exception of “no free sockets” when i try to close the current connection, i think it is maybe i have the thread running.
I’d like to have this thread running always and just close the current connection and open another one.
:wink:


#2

your code is incomplete. you are not showing how you close the socket and then connect to another host.


#3

sorry, well i just do this:

i have a button, when i press it the first time it open the connection with the first host and send data:


TCPEndpoint = new IPEndPoint(IPAddress.Parse("192.168.1.103"), 23);
ServidorTCPIP.Connect(TCPEndpoint);
ServidorTCPIP.Send(Encoding.UTF8.GetBytes("hello world\r\n"));

Then the second time the button is pressed it close the current connection and do the same to open a new connection:


ServidorTCPIP.Close();
TCPEndpoint = new IPEndPoint(IPAddress.Parse("192.168.1.110"), 58);
ServidorTCPIP.Connect(TCPEndpoint);
ServidorTCPIP.Send(Encoding.UTF8.GetBytes("hello world\r\n"));


#4

I am not sure but I think ServidorTCPIP.Close(); frees up the socket resources. You can not connect() after that. You have to create a new Socket() then connect.


#5

yes, the problem was that when i use the close method it disables all the resources, now i’m doing this before open i new connection:


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

thanks for your reply. 8)


#6

Now my problem is that i have the thread waiting for data and the first time works well, but after closing the connection the data is missing, i now it is because the close method frees up the socket resources:


        static void LecturaTCP()
        {
            while (true)
            {
               //all this does't work because the close method frees up the socket resources
                if (ServidorTCPIP.Poll(-1, SelectMode.SelectRead))                
               {
                    byte[] entrada = new byte[ServidorTCPIP.Available];
                    int cuenta = ServidorTCPIP.Receive(entrada);
                    char[] caracteres = Encoding.UTF8.GetChars(entrada);
                    string cadena = new string(caracteres, 0, cuenta);
                    Debug.Print("Data recieve: " + cadena + "\r\n");
                }
            }
        }

so my question now is how to have the thread waiting for data for each connection, something like creating a new thread when i call the connect method or something like that, i don’t know how. :o


#7

Have a look at the NetMF samples: C:\Users[YOURUSERNAME]\Documents\Microsoft .NET Micro Framework 4.1\Samples


#8

I’m running into some fundamental problems getting started with network communication using the FEZ Panda II. I’m trying to connect a socket to a remote endpoint (that part works, thanks to ReintializeNetworking). But when I attempt to send bytes on the socket, I get an exception telling me the “Socket is closed”. The code below exhibits the problem.

I tried the code that JAMG posted with no success in sending either.

The only way I’ve successfully sent data on a socket is if I attempt to send on a socket that is returned by Socket.Accept. But I need my program to initialize the connection and send, as in my stripped-down code below.

Any help would be appreciated!


using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.Net.Sockets;
using GHIElectronics.NETMF.Net;
using GHIElectronics.NETMF.Hardware;
using GHIElectronics.NETMF.FEZ;
using System.Text;

namespace FEZ_Panda_II_Application1
{
    public class Class1
    {
        public static void Main()
        {
            byte[] ip = { 192, 168, 111, 211 };
            byte[] subnet = { 255, 255, 255, 0 };
            byte[] gateway = { 192, 168, 111, 1 };
            byte[] mac = { 43, 185, 44, 2, 206, 127 };

            WIZnet_W5100.Enable(SPI.SPI_module.SPI1, (Cpu.Pin)FEZ_Pin.Digital.Di10, (Cpu.Pin)FEZ_Pin.Digital.Di9, true);
            GHIElectronics.NETMF.Net.NetworkInformation.NetworkInterface.EnableStaticIP(ip, subnet, gateway, mac);

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

            WIZnet_W5100.ReintializeNetworking();
            IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("192.168.111.100"), 6110);
            sock.Connect(endPoint);
            byte[] buffer = { 1, 2, 3, 4 };
            sock.Send(buffer, 0, buffer.Length, SocketFlags.None);
        }
    }
}


#9

WIZnet_W5100.ReintializeNetworking(); is the problem : you kill the socket you just opened.
This method shall be used to reinitialize the wiznet 5100 shield, so everything you did before that is lost…

Here is a sample TCP connect I got from one of my previous programs:


// Get server's IP address.
IPHostEntry hostEntry = Dns.GetHostEntry(server);
// Create socket and connect to the server's IP address and port
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(new IPEndPoint(hostEntry.AddressList[0], 80));
DateTime timeoutAt = DateTime.Now.AddSeconds(30);
socket.Send(requestHeaderRAW, requestHeaderRAW.Length, 0); // Send request
while (socket.Available == 0 && DateTime.Now < timeoutAt) System.Threading.Thread.Sleep(100);
buffer[0] = 0;
if (socket.Available > 0) socket.Receive(buffer, socket.Available > 1024 ? 1024 : socket.Available, SocketFlags.None);
socket.Close();

#10

Thanks for your reply, Nicolas. I have been suspicious of the call to WIZnet_W5100.ReintializeNetworking(). But without it, my socket doesn’t connect. I get an exception saying “Timeout occurs during connection establishment”.

I tried running your sample TCP connect code, modified as little as possible (below) and had the same problem, failing at socket.Connect().


// Get server's IP address.
IPHostEntry hostEntry = Dns.GetHostEntry("192.168.111.100");
// Create socket and connect to the server's IP address and port
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(new IPEndPoint(hostEntry.AddressList[0], 80));
DateTime timeoutAt = DateTime.Now.AddSeconds(30);
byte[] requestHeaderRAW = { 1, 2, 3, 4 };
socket.Send(requestHeaderRAW, requestHeaderRAW.Length, 0); // Send request
while (socket.Available == 0 && DateTime.Now < timeoutAt) System.Threading.Thread.Sleep(100);
requestHeaderRAW[0] = 0;
if (socket.Available > 0) socket.Receive(requestHeaderRAW, socket.Available > 1024 ? 1024 : socket.Available, SocketFlags.None);
socket.Close();


#11

To what equipment at you trying to connect ?
Can you have a look with a protocol analyser to see what is happenning ? (wireshark is free and great)

Also if you are using the ethernet shield “Fez Connect” you shall change FEZ_Pin.Digital.Di9 by FEZ_Pin.Digital.Di7 in the WIZnet_W5100.Enable call


#12

Thanks again for the reply, Nicolas. The code I posted earlier is not my full project, but just the basic network communication extracted from a larger project. I had been using the Netduino platform, and had everything working fine. I’m porting to the FEZ to take advantage of UDP functionality and the persistent storage on the FEZ board.

I’m using a test program on my PC to send configuration to the FEZ over IP: to tell the FEZ the IP address of a network appliance (a digital recorder running Windows) that the FEZ should connect to. This is accomplished by the following: FEZ opens a listening socket, calls accept, and the test program connects to it and sends the configuration to the FEZ. The FEZ receives it fine.

The FEZ then opens another socket to connect to the digital recorder to begin communicating with it. It successfully establishes the socket connection (only when I include the call to ReintializeNetworking. I don’t understand why this is required either, but it doesn’t work without it). When it attempts to send on the socket to the digital recorder, it gets a Socket Closed exception.

I installed Wireshark and was able to observe the activity described above.

Again, all this code worked on the Netduino. Changing from Di9 to Di7 didn’t seem to make a difference, either.


    while (true)
    {
        //get configuration from listen socket
        if (socketListener.ListenSocketAccepted)
        {
            systemConnection.PollSock(socketListener.AcceptSock, listenParser);
        }
        if (!Connected)
        {
            //attempt connection if we know what we're connecting to
            if (RecorderIP != string.Empty && RecorderPort != 0)
            {
                if (systemConnection.ConnectSocket(ip, RecorderIP, RecorderPort))
                {
                    Connected = true;
                    systemConnection.SendProtocolRegistrationMessage();
                    ConnectionTest = new Thread(TestConnection);
                    ConnectionTest.Start();
                }
                System.Threading.Thread.Sleep(10000);
            }
        }
    }


class SocketListener
{
    Socket listenSocket;
    Socket acceptSocket;
    System.Threading.Thread AcceptThread;

     public void InitListenSocket()
    {
        listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        listenSocket.Bind(new IPEndPoint(IPAddress.Any, 6110));
        listenSocket.Listen(1);
        AcceptThread = new Thread(CheckAccept);
        AcceptThread.Start();
    }
     public void CheckAccept()
    {
        acceptSocket = listenSocket.Accept();
        if (acceptSocket != null)
        {
            ListenSocketAccepted = true;
        }
    }
}


public class SystemConnection
{
    public bool ConnectSocket(byte[] thisIP, string RecorderIP, int RecorderPort)
    {
        //initialize socket
        try
        {
           sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        }
        catch(System.Net.Sockets.SocketException e)
        {
        }

        //connect socket
        try
        {
            WIZnet_W5100.ReintializeNetworking();
            IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(RecorderIP), RecorderPort);
            sock.Connect(endPoint);
            return true;
        }
        catch (System.Net.Sockets.SocketException e)
        {
            return false;
        }
    }
}


#13

You definitly have to get rid of WIZnet_W5100.ReintializeNetworking();

It is where you problem is.
If it is not connecting without WIZnet_W5100.ReintializeNetworking();, you have to find why, not use this fonction, it can just not work !

Also on FEZ you are limited to a very tight 3 simultaneous sockets (one reserved for internal use, for things like dns). I am not seeing your whole program here, but are you sure you are closing your sockets (incoming) when you are done with them ?

You can also try to enable the Wiznet class by setting the last parameter to false, which will free up one more socket. At least for a test.


#14

Thanks, Nicolas. Gotcha. Wish I could figure out how to get it to connect a socket without that call to WIZnet_W5100.ReintializeNetworking();

I’ll go back to the bare bones simplified code that just tries to connect a socket and send something on it:


    public class Class1
    {
        public static void Main()
        {
            byte[] ip = { 192, 168, 111, 211 };
            byte[] subnet = { 255, 255, 255, 0 };
            byte[] gateway = { 192, 168, 111, 1 };
            byte[] mac = { 43, 185, 44, 2, 206, 127 };

            WIZnet_W5100.Enable(SPI.SPI_module.SPI1, (Cpu.Pin)FEZ_Pin.Digital.Di10, (Cpu.Pin)FEZ_Pin.Digital.Di7, false);
            GHIElectronics.NETMF.Net.NetworkInformation.NetworkInterface.EnableStaticIP(ip, subnet, gateway, mac);

            //WIZnet_W5100.ReintializeNetworking();
            Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("192.168.111.100"), 6110);
            sock.Connect(endPoint);
            byte[] buffer = { 1, 2, 3, 4, 0 };
            try
            {
                sock.Send(buffer, 0, buffer.Length, SocketFlags.None);
            }
            catch (Exception e)
            {
                Debug.Print("Test");
            }
        }
    }

Sadly this code times out on sock.Connect(endPoint); . I guess that is the first problem I need to figure out.


#15

I have tried your source code and it SHOULD work. But it’s not. >:(

I was able to make it work by adding the 2 following lines just after the EnableStatisIP:

GHIElectronics.NETMF.Net.NetworkInformation.NetworkInterface.EnableStaticDns(new byte[] { 8, 8, 8, 8 });
IPHostEntry hostEntry = Dns.GetHostEntry("yahoo.com");

(replace 8.8.8.8 by your DNS server).
the name yahoo.com is just to make the fez look up “any name”. Then after that it accepts to connect to your host. Just leave yahoo.com for now and tell me if it works…

I realize now that previously I never had connected to something before making a dns request first. Is the DNS request unlocking something in the wiz5100 stack ?

I really don’t understand why. Maybe Joe@ GHI can have a look ?
Why can’t we make any tcp connect to an ip address if a dns call was not made before ???


#16

Try it agina by changin gthe mac address.
Use this for example:

byte[] mac = { 0x00, 0x26, 0x1C, 0x7B, 0x29,0xE8 };

I used this tool to generate a correct MAC address. I know this sounds strange. but for some reason not any number can be used in the mac address.
I use this tool to generate a mac address:
http://www.macvendorlookup.com/


#17

Good find, Nicolas. Thanks for taking some more time to examine this issue.

And I guess the MAC address change renders the issue moot. I tried the one you suggested, Joe, and it has cleared up my issues. Thanks for that.

Thank you all for helping me out with this.


#18

BiscuitDough,
That 's good news we figured out what the problem was. 8)

What is the example code you used with that wrong MAC address. we need to fix that for other users.

Thanks,
Jot


#19

Joe,
I’m pretty sure the wrong MAC address was something I copied from another post somewhere on this forum. I don’t think it was from GHI example code, but you could search the code base for the MAC address in my code listings above, to ensure it’s not in there.

It makes sense that it wouldn’t work. But the symptoms that it exhibited didn’t lead me to suspect the MAC address, because I was able to successfully use a socket to listen, and subsequently was able to send data on the socket returned by Socket.Accept(). The problem came in attempting to connect a socket to an explicit remote endpoint (timeout). I was further confused when calling ReintializeNetworking() helped it connect, but it would throw a “socket closed” exception when attempting to send.

By the way, here’s a nitpick - the ReintializeNetworking() function name is spelled wrong in the API. :slight_smile:


#20

If you use the forum search box to search for “43, 185, 44, 2, 206, 127” (the MAC address that wasn’t working) you’ll find it all over the place - sometimes being pointed out as a problem and sometimes not.

On the wiki it appears on the networking page in all the examples: http://wiki.tinyclr.com/index.php?title=Networking

Andrew