On the other side of the client, we will analyze the establishment process of tcpclientsock.
Class tcpclientsock: Public basesock {
PRIVATE:
Sockaddr_in serversockaddr;
Protected:
Char * prebuffer;
Int prebuffersize;
Mutable int prereceivedlength;
Public:
Tcpclientsock (
Const char * server_ip,
Unsigned short server_port,
Int pre_buffer_size = 32 );
Virtual ~ Tcpclientsock ();
Int tcpreceive () const;
Int tcpsend (const char * send_data,
Const Int & data_length) const;
};
We can see that the tcpclientsock class is very similar to tcpserversock. The difference between constructors is that tcpclientsock needs to provide the IP address and port number of the server.
Tcpclientsock: tcpclientsock (
Const char * server_ip,
Unsigned short server_port,
Int pre_buffer_size ):
Prebuffersize (pre_buffer_size ),
Prereceivedlength (0)
{
Prebuffer = new char [prebuffersize];
Sockfd = socket (pf_inet, sock_stream, ipproto_tcp );
If (sockfd <0 ){
Sockclass: error_info ("Sock () failed .");
}
Memset (& serversockaddr, 0, sizeof (serversockaddr ));
Serversockaddr. sin_family = af_inet;
Serversockaddr. sin_addr.s_addr = inet_addr (server_ip );
Serversockaddr. sin_port = htons (server_port );
If (connect (sockfd,
(Struct sockaddr *) & serversockaddr,
Sizeof (serversockaddr) <0 ){
Sockclass: error_info ("Connect () failed .");
}
}
Tcpclientsock ::~ Tcpclientsock ()
{
Delete [] prebuffer;
Close (sockfd );
}
Tcpclientsock uses Socket () to establish sockfd, specify serversockaddr of the server, and then send a handshake request to the server specified by serversockaddr through Connect. It should be noted that when you call connect (), the system will check whether the tcfd of tcpclientsock has been bound to the local sockaddr. In fact, we can also use bind () bind the IP address of the local machine to the specified port number on this sockfd, but we do not care about this IP address and port number (besides, many hosts do not have a public IP address, especially in China ), therefore, we usually do not bind it by ourselves, so the system will help us complete the binding and assign an idle port number as the port number of the local address.
In this way, tcpclientsock has the address information of the incoming (local address, usually automatically bound by the system, you can also specify) and destination (specified server address), so you can send and receive information. Therefore, the first datagram sent by tcpclientsock is the handshake request datagram sent to the server listening socket. After tcplistensock receives the datagram, it passes the relevant information to tcpserversock to create a new sockfd. As mentioned in the previous section, after the new sockfd is set up, a datagram is immediately returned to the client: the first handshake request is accepted, and the second handshake request is sent.
After receiving the second handshake request, connect () will return, otherwise it will be blocked, and very "Try your best" to connect to the server. This "Best Effort" is related to the system. In my experiment, Windows is very fast, just a few seconds, and Debian is close to 6 minutes!
At the same time that connect () returns, it sends a third handshake message to the server, which is an acknowledgment of the second handshake request. Therefore, the first and second handshakes contain connection requests, while the second and third handshakes contain the recognition of the handshake requests. They are all telling the other party: I know and agree that you are connected to me.
So far, the three-way TCP handshake concept is fully implemented in the socket to establish a TCP communication channel for data streams.