Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Checking if TcpSocket is connected  (Read 15489 times)

0 Members and 1 Guest are viewing this topic.

Tuffywub

  • Newbie
  • *
  • Posts: 26
    • View Profile
    • Email
Checking if TcpSocket is connected
« on: May 08, 2013, 04:58:57 am »
Hey, I was wondering, what is the best and fastest way to check if an sf::TcpSocket is connected? Can I just set it to non-blocking mode, and then call receive to get a status code? Would that work, and is it efficient? Is there a better, simpler way? I looked at the documentation, and there doesn't seem to be something like:

bool isConnected();

So what should I use? Sorry if this has been asked, I didn't see anything about it online, but give me a link if there is. Thanks in advance.  :)

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Checking if TcpSocket is connected
« Reply #1 on: May 08, 2013, 07:11:44 am »
If you perform a blocking connect, it will just block until either the timeout expires or it is successful or unsuccessful, you can determine this from the Status code that is returned.

If you set the socket to non-blocking, you tell it to perform an asynchronous connect, meaning you will not be notified upon a successful or unsuccessful connection attempt. That is how event based network APIs work and also how IOCP in Windows functions, but because SFML makes use of the POSIX network API there is no way to directly do such a thing.

In case you set the socket to non-blocking you don't really need to check whether the socket is connected until you really want to do something with it. You need to ask yourself, what would you do if you did have a function like you described? The only things you might do would be to decide whether to make use of the socket or not, and since this is implicitly done through the attempt to use the socket and checking the return code, such a function wouldn't really make sense in non-blocking operation if you ask me.

Since both cases are covered, it really doesn't make sense to have a isConnected() function, because it is up to the programmer to decide how they want to determine that for their specific scenario and cannot be done in a universal way.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Laurent Gomila - SFML developer

Tuffywub

  • Newbie
  • *
  • Posts: 26
    • View Profile
    • Email
Re: Checking if TcpSocket is connected
« Reply #3 on: May 09, 2013, 03:39:36 am »
Thanks Laurent, I have no clue how I missed that. I feel stupid now :P

And that is a good point, I probably won't have to use this very often, though I think it would be useful in this case. I am using this on the server end, and I want to be able to check if a client has disconnected as soon as possible, without having to wait to check with send() or receive().

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Checking if TcpSocket is connected
« Reply #4 on: May 09, 2013, 04:15:38 am »
Checking to see whether the opposite side has disconnected is even trickier. When programming using the POSIX API, you would normally recv() as usual and check to see if it returns with 0 bytes received, which in turn informs you that the opposite side wants to terminate the connection. You have to terminate your end of the connection as well, once you are done sending the last bytes to the opposite side. This is done by calling shutdown( socketHandle, SHUT_WR ) on the socket. Once both sides have done this the connection is truly disconnected and only then should the socketHandles be closed().

SFML doesn't perform a clean TCP connection shutdown as I already stated here, which could lead to problems in some cases.

In order to check if the opposite side wants to disconnect with SFML, you would have to do something like:
std::size_t dummy;

if( socket.receive(&dummy, 0, dummy) == sf::Socket::Disconnected ) {
        // Opposite side wants to disconnect.
        // Time to lament that there is no clean way
        // to perform a clean connection termination with SFML.
}
 
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Tuffywub

  • Newbie
  • *
  • Posts: 26
    • View Profile
    • Email
Re: Checking if TcpSocket is connected
« Reply #5 on: May 09, 2013, 04:42:26 am »
Wait.....

so if the other end calls tcpSocket.disconnect(),
then on my end, getRemoteAddress() would not return sf::IpAddress::None???

I'm confused.
When and what does getRemoteAddress() return?
Does it only return sf::IpAddress::None when it has never started a connection, or if there is no connection present?

Going by the documentation, it seems that this would return sf::IpAddress::None whenever there is no connection, even if the other side has disconnected.
To quote:

Quote
Get the address of the connected peer.

It the socket is not connected, this function returns sf::IpAddress::None.

Would someone mind clearing this up for me? Thx for your time  :D

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Checking if TcpSocket is connected
« Reply #6 on: May 09, 2013, 06:39:58 am »
Perhaps the documentation is a bit unclear when it comes to this. It gives you an address when the socket is connected, however it does not necessarily return sf::IpAddress::None if the opposite side chooses to close the connection because SFML doesn't differentiate between "wants to terminate connection" and "disconnected". After the remote side expresses its wish to terminate the connection, you can still send it data because the connection will still be half-open. The connection is only truly closed when both sides agree not to send data to each other any more.

The way it is now. If the opposite side is also using SFML for TCP communication, it will close() the socket handle resulting in the operating system discarding all incoming and outgoing queued packets. If any new data arrives at the network interface destined for that socket, it is required to acknowledge with a RST, telling the other side "nobody lives here any more and I guess they were in a hurry and didn't wait for you to say goodbye". This is a "brutal" way of closing a connection if you ask me. Any time I see a RST I always check to see if everything is functioning properly because it is an exceptional occurrence.

Now comes the strange part. If the opposite side is not using SFML for TCP communication and performs a standard shutdown() like I described in my previous post, it still allows the remote side to send it data and will wait patiently until the remote side "said goodbye" and both will close() at the same time. This means that even if it looks to SFML like the remote side disconnected (because you get sf::Socket::Disconnected back from receive()), a send() to the socket will return sf::Socket::Done and not sf::Socket::Disconnected because the remote side is polite and allows you to say goodbye before it leaves ;).

I don't know the exact details of when getpeername() (what SFML uses internally) returns with a not-connected-error but theoretically it would be incorrect if it did so when the connection is still half-open because that is not the same as the closed state.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Tuffywub

  • Newbie
  • *
  • Posts: 26
    • View Profile
    • Email
Re: Checking if TcpSocket is connected
« Reply #7 on: May 11, 2013, 12:05:25 am »
So is there a safe way to check if a server has ended the connection from the client? I know I could always just do a timeout myself, but it seems as if there is no way to tell if the other side has disconnected a TCP connection with SFML?

If I am not able to send a disconnect packet through the connection before disconnecting (program crashes, power outage  ;)), then it is up to the other end to figure out that there was a disconnection, right?

It seems that there should be a simple way to know when the connection was requested to end from the other side...

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Checking if TcpSocket is connected
« Reply #8 on: May 11, 2013, 12:52:54 am »
You are right, there is no way to tell if the other end suddenly disappears. TCP will wait a while before resetting the connection, and even in that case only if you send the other side data because it notices that the other side is not there when it doesn't receive the corresponding ACK.

You will notice this in many applications that use TCP and don't implement their own ping or keep-alive system on top of TCP. If you pull the cable out of your computer it will take a variable amount of time for the application to tell you the server isn't reachable any more.

The best thing you can do is what every experienced network programmer recommends, implement your own connection management on top of TCP. That way you can have keep-alive packets, disconnect requests, etc. and don't have to deal with these corner cases because you try to bend TCP to fit what you want to do.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).