Closesocket, Shutdown, Tcp::socket.close ()

Source: Internet
Author: User
Tags ack data structures documentation socket

Come on, let's talk about this shutdown and closesocket.
Parse from function call (MSDN): Once a socket connection is completed, the socket should be closed and all resources occupied by its socket handle should be freed. A resource that really frees an already opened socket handle can call closesocket directly, but understand that the closesocket call can have a negative impact, the specific impact and how the call relates, the most obvious effect is data loss, Therefore, it is common to call shutdown before closesocket to close the socket.
Shutdown: In order to ensure that both sides of the communication are able to receive all the data sent by the application, it is a good practice to notify both recipients that they are not sending data. This is the so-called "normal shutdown" socket method, and this method is by the shutdown function, the parameters passed to it has sd_receive,sd_send,sd_both three, if it is sd_receive means that the socket is not allowed to call the Accept function. This has no effect on the protocol layer, and for TCP sockets, whether the data is waiting to be accepted or is about to arrive, reset the connection (note that for the UDP protocol, the incoming data is still accepted and arranged, so UDP sockets are shutdown meaningless). If you select Se_send, you are not allowed to call the Send function again. For TCP sockets, this means that a fin packet is generated after all data has been sent out and acknowledged by the receiving end. If you specify Sd_both, the answer goes without saying.
Closesocket: The invocation of this function releases the description of the socket, which is well known (usually the programmer who browses MSDN), so after calling this function, the call fails with this socket, and usually the error returned is Wsaenotsock. The resources associated with the closesocket socket description typeface are released at this time, including discarding the data in the transmission queue .... For the threads in the current process, all the actions that are closed, or the overlapping operations that are suspended, and any events associated with them, the execution of the completion routine or completion port fails. In addition, the SO_LINGER flag also affects the behavior of closesocket, but for the traditional socket program, here does not add explanation
Therefore, it can be seen that the shutdown has a reasonable integrity to cut off the connection.
The following analysis of the behavior of shutdown and closesocket from the TCP Protocol (behavior): Closesocket or shutdown (when using sd_send as a parameter) sends a FIN packet to the communicating party, At this point the state of the socket will be changed from established to Fin_wait_1, and then the other party sends an ACK packet as a response, the socket becomes fin_wait_2, if the other side also closes the connection, the other side will issue fin, we will respond to an ACK and set the socket to time _wait. So it can be seen that the TCP behavior of the Closesocket,shutdown is the same, the difference is the function part, shutdown will ensure that the data transmission queue in Windows is not lost, and closesocket will risk discarding all the data, So if you are willing to closesocket can completely replace the shutdown, but in the data interaction is very complex network protocol program, it is best to shutdown secure some.


Closesocket, Shutdown, Tcp::socket.close ()

TCP Closes the connection in 2 ways, one is to turn off the fin, the other responds Finack, and the closing end then returns the ACK, which is graceful to close the connection. Both parties can guarantee that all data is sent and received to completion. The other is hard to close and the closed side sends RSet directly. Disconnect immediately after the other person receives it.

The first thing you should know about the Win32 API Closesocket is that it's not clear enough in the MSDN documentation.

First of all, the default: L_onoff returns for 0,closesocket immediately, but the underlying continues to contract, and attempts to gracefully close the connection. In this case, the connection has been closed for the application, but the underlying socket's associated resources have not been released and do not know how long to wait. This method is not a problem for the general program, for the server, because there may be a very many sockets (more than 100k), so that processing may lead to the system is not available socket resources.

Second, L_onoff is not 0, this time depends on the value of L_linger, the system will be as graceful as possible to close the connection, if the connection can not be closed in l_linger time, then hard shutdown. That is, if L_linger is 0 at this point, it must be hard closed, and Closesocket will return immediately, releasing all resources. If L_linger is not 0, then gracefully shuts down and returns, frees all resources if timed out, then hard shuts down, Closesocket returns, frees all resources. Note that in this case, the closesocket may be synchronous.

Shutdown has 2 functions. The subsequent send or recv is forbidden first, but note that it does not affect the underlying, that is, the previously issued asynchronous SEND/RECV does not return. Second, after all the sent packets are confirmed by the other side, the fin is sent to the other side, trying to gracefully close the connection. But shutdown itself does not affect anything at the bottom, so shutdown and gracefully closes the connection, the socket and its associated resources remain, and must be called closesocket to be freed.

The above is a description of the MSDN documentation. But the actual process is not entirely true. The test program uses ASIO to implement a TCP server, in Handle_send, which means that a package has been asynchronously returned to indicate the success of the send (successfully sent to the system buffer), when the call Socket_.close, the results found that the package is not actually sent (or possibly sent), The system emits a rset rather than fin. If Socket_.shutdown (both) is called before Socket_.close, a FIN packet is issued. It's a bit strange here, the lab platform is Windows 20008 and Windows XP. The values of L_onoff and L_linger are checked with socket_.get_option in the experiment, and they are indeed the default values.

Because there are many times when such a requirement exists, that is, the client or server closes the connection after the last packet is issued, typically by calling Socket_.close after the last packet is issued, or no longer making any asynchronous calls to let socket_ automatically enter the destructor. This is likely to be a problem. First call once after the last package is sent shutdown may be helpful in the case of fast speed. But there are 2 shortcomings, on the one hand, the speed may not be fast, the package may not be issued soon, because shutdown does not affect the previously issued package, so fin may not be able to emit, another disadvantage is that the subsequent closesocket does not really mean that the resources have been released.

To sum up, the good practice is to handle_send inside, if it is the last package, then set a flag, shutdown, and then start a 1s deadline_timer:

Socket_.shutdown (Boost::asio::ip::tcp::socket::shutdown_both, Boost::system::error_code ());

if (!graceful_close_)

{

Handle_hard_close (Boost::system::error_code ());

}

Else

{

Timer_hard_close_.expires_from_now (boost::p osix_time::seconds (1));

Timer_hard_close_.async_wait (

Strand_.wrap (Boost::bind (

&tcp_client::handle_hard_close,

Shared_from_this (),

Boost::asio::p laceholders::error)));

}

And then

void Handle_hard_close (const boost::system::error_code& error)

{

if (!error)

{

Boost::asio::socket_base::linger option (true, 0);

socket_.set_option (option);

Socket_.close ();

}

}

Appendix:

ASIO part of the source code:

Destructors for Tcp::socket:

Win_iocp_socket_service.hpp

void Close_for_destruction (implementation_type& impl)

{

if (Is_open (Impl))

{

Check If the reactor is created, in which case we need to close the

Socket on the reactor as well to cancel any operations this might be

Running there.

reactor_type* reactor = static_cast<reactor_type*> (

Interlocked_compare_exchange_pointer (

Reinterpret_cast<void**> (&reactor_), 0, 0);

if (reactor)

Reactor->close_descriptor (impl.socket_, Impl.reactor_data_);

The socket destructor must not block. If the user has changed the

Linger option to block in the foreground, we'll change it back to the

Default So, the closure is performed in the background.

if (Impl.flags_ & Implementation_type::close_might_block)

{

:: Linger opt;

Opt.l_onoff = 0;

Opt.l_linger = 0;

Boost::system::error_code Ignored_ec;

Socket_ops::setsockopt (impl.socket_,

Sol_socket, So_linger, &opt, sizeof (opt), IGNORED_EC);

}

Boost::system::error_code Ignored_ec;

Socket_ops::close (impl.socket_, IGNORED_EC);

impl.socket_ = Invalid_socket;

Impl.flags_ = 0;

Impl.cancel_token_.reset ();

#if defined (Boost_asio_enable_cancelio)

impl.safe_cancellation_thread_id_ = 0;

#endif//Defined (Boost_asio_enable_cancelio)

}

}

Tcp::socket.close

Win_iocp_socket_service.hpp

Boost::system::error_code Close (implementation_type& impl,

boost::system::error_code& EC)

{

if (Is_open (Impl))

{

Check If the reactor is created, in which case we need to close the

Socket on the reactor as well to cancel any operations this might be

Running there.

reactor_type* reactor = static_cast<reactor_type*> (

Interlocked_compare_exchange_pointer (

Reinterpret_cast<void**> (&reactor_), 0, 0);

if (reactor)

Reactor->close_descriptor (impl.socket_, Impl.reactor_data_);

if (Socket_ops::close (impl.socket_, EC) = = Socket_error_retval)

return EC;

impl.socket_ = Invalid_socket;

Impl.flags_ = 0;

Impl.cancel_token_.reset ();

#if defined (Boost_asio_enable_cancelio)

impl.safe_cancellation_thread_id_ = 0;

#endif//Defined (Boost_asio_enable_cancelio)

}

EC = Boost::system::error_code ();

return EC;

}

The above code clearly illustrates the implementation of the ASIO.

First, if it is a destructor, then the socket is set back to the default state, that is, an gracefully closed connection with unpredictable time, regardless of whether the Setsockopt,asio has been set previously. If socket.close, then call closesocket directly.

Another notable point is that both functions set the socket to Invalid_socket, thus avoiding the problem of multiple shutdowns.

The problem with multiple shutdowns is this: first assume socket a = 0x1234, call closesocket to close the socket, and then createsocket to get a socket B also for 0x1234, The code (which may be another thread or IOCP to get a wrong return) tries to close socket a again, shutting down socket B. This situation is common under the Windows platform, where socket B is probably also 0x1234.

==============================================

When the CP connection is disconnected, call the Closesocket function and have discussed graceful disconnection and forced disconnection, so how do you set the disconnection mode? is a linger structure property by setting the socket descriptor.

Linger structure data structures are as follows:

struct linger

{

int L_onoff;

int L_linger;

};

There are three ways to combine:

First Kind

l_onoff = 0;

L_linger Ignore

In this way, when the closesocket is returned immediately, the underlying will send the unsent data after the completion of the release of resources, that is, graceful exit .


The second Kind

L_onoff non-0

l_linger = 0;

In this way, the closesocket is returned immediately when the call is made, but the data is not sent, but it is forced to close the socket descriptor via a rest package, which is forced exit .


Third Kind

L_onoff non-0

L_linger > 0

In this way, the closesocket is not returned immediately when the call is made, and the kernel is delayed for a period of time , which is determined by the L_linger value . If the time-out period arrives before the unsent data is sent (including the Fin package) and the other end is confirmed, the closesocket returns to the correct, graceful exit of the socket descriptor. Otherwise, Closesocket will return the error value directly, no data is lost, and the socket descriptor is forced to exit. Note that if the socket descriptor is set to a non-clogging type, closesocket will return the value directly.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.