Home > Software engineering >  Socket-Listener only works for the first time, at second time the connection gets refused
Socket-Listener only works for the first time, at second time the connection gets refused

Time:01-18

I am a C#/WPF developer and have not many experience in network-communication (socket/tcp) and just trying to get a simple working example for a TCP-Listener-project for exchanging messages between server and client.

I think Im nearly there where I want to come to, but have an open issue left: When I start the server and after that the client, the messages get exchanged like wanted. After that I close the client and restart it, the second connection gets refused (at "await client.ConnectAsync(ipEndPoint)") with following message (sorry, its translated from german to english): "A connection could not be established because the target computer refused the connection"

Do you maybe have any hint for me, what I am doing wrong? I also tried closing clients connection in the client app, but same behaviour.

Server-code:

public async Task<bool> StartServer()
    {

        IPHostEntry ipHostInfo = await Dns.GetHostEntryAsync("127.0.0.1");
        IPAddress ipAddress = ipHostInfo.AddressList[0];
        IPEndPoint ipEndPoint = new(ipAddress, 8888);

        using Socket listener = new(
            ipEndPoint.AddressFamily,
            SocketType.Stream,
            ProtocolType.Tcp);

        listener.Bind(ipEndPoint);
        listener.Listen(100);

        Socket client = await listener.AcceptAsync();

        while (true)
        {
            var buffer = new byte[1_024];
            var received = client.Receive(buffer, SocketFlags.None);
            var response = Encoding.UTF8.GetString(buffer, 0, received);

            var eom = "<|EOM|>";
            if (response.IndexOf(eom) > -1 /* is end of message */)
            {
                AddLogText($"Socket server received message: \"{response.Replace(eom, "")}\"");
                var ackMessage = "Hallo Client!<|ACK|>";
                var echoBytes = Encoding.UTF8.GetBytes(ackMessage);
                await client.SendAsync(echoBytes, 0);
                AddLogText($"Socket server sent acknowledgment: \"{ackMessage}\"");
                break;
            }

        }

        client.Shutdown(SocketShutdown.Both);
        client.Close();

        return true;
    }

Client Code:

private async Task<bool> StartClient()
    {
        IPHostEntry ipHostInfo = await Dns.GetHostEntryAsync("127.0.0.1");
        IPAddress ipAddress = ipHostInfo.AddressList[0];
        IPEndPoint ipEndPoint = new(ipAddress, 8888);

        using Socket client = new(
        ipEndPoint.AddressFamily,
        SocketType.Stream,
        ProtocolType.Tcp);

        await client.ConnectAsync(ipEndPoint);
        while (true)
        {
            var message = "Hallo Server?<|EOM|>";
            var messageBytes = Encoding.UTF8.GetBytes(message);
            _ = await client.SendAsync(messageBytes, SocketFlags.None);
            Console.WriteLine($"Socket client sent message: \"{message}\"");
            var buffer = new byte[1_024];
            var received = await client.ReceiveAsync(buffer, SocketFlags.None);
            var response = Encoding.UTF8.GetString(buffer, 0, received);
            if (response.Contains("<|ACK|>"))
            {
                Console.WriteLine($"Socket client received acknowledgment: \"{response}\"");
                break;
            }
        }

        return true;
    }

CodePudding user response:

Your StartServer method returns after the first client socket finishes, disposing the listening socket.

Usually, you want to keep the listening socket open and listening, and call AcceptAsync in an infinite loop.

But I have to caution you: socket programming is extremely difficult. For example, your socket reading code is far too simplistic to properly handle message framing. I recommend self-hosting ASP.NET or something else that handles the protocol-level details for you.

CodePudding user response:

You might have misunderstood how the server works. It should be like this:

  1. Create a socket and call Bind and Listen. This part is okay.
  2. Call Accept, which waits for a client to connect, and then returns a socket connected to that specific client.
  3. Send and receive data from the client.

If you want to wait for another client, after you are done with the first one, then of course you need to call Accept again.

It is also common for servers to handle several clients at the same time, for example by using threads (or async). One thread just calls Accept over and over, and whenever a new client connects, it starts a new thread to handle that client. You don't need this for a toy program, that only handles one connection at a time. But you do need it for a real server, otherwise one client can connect, and be really slow, and your server won't handle any other clients while that is happening.

If you are not doing a "graceful close" there is no need to call Shutdown - you can just Close the client's socket to disconnect the client. When you Close the main server socket you stop accepting new connections. Shutdown doesn't apply to the main server socket.

  • Related