网络函数[04]connect解析

0 -- connect函数解析
#include <sys/socket.h>
int connect(int socket, const struct sockaddr * address, socklen_t address_len);

返回值
 0:建立连接成功;
-1:建立连接失败或者发生其他错误,请参考errno;


网络函数connect用来建立一个TCP客户与TCP服务器之间的连接。
参数socket,是由socket函数返回的套接口文件描述符;
参数address,是一个指向欲连接服务器套接口地址的指针;
参数address_len,是参数address表示的套接口地址结构体的大小;

在讲述connect的使用方法,以及在实际使用中可能遇到的问题之前,我们先看下使用connect进行阻塞连接的例子。

#include <sys/socket.h>	//socket,connect的定义
#include <arpa/inet.h>	//inet_pton的定义
#include <string.h>       //memset的定义
#include <netinet/in.h>	//htons,struct sockaddr_in的定义
#include <errno.h>        //errno,strerror的定义

#include <string>
#include <iostream>

/***
 ** 函数返回值:
 **  -1:内部调用网络函数错误,请参考相关errno;
 **  -2:网络地址不合法
 ** >=0:网络套接口文件描述符
 **/
int do_connect(const std::string & s_host, const unsigned short usi_port)
{
    //转换指定
    struct sockaddr_in sock_addr;
    memset(&sock_addr, 0, sizeof(struct sockaddr_in));
    sock_addr.sin_family  = AF_INET;
    sock_addr.sin_port    = ::htons(usi_port);

    switch (::inet_pton(AF_INET, s_host.c_str(), &sock_addr.sin_addr))
    {
        case  0: return -2;
        case -1: return -1;
    }

    //建立网络套接口文件描述符
    int sock_fd = ::socket(AF_INET, SOCK_STREAM, 0);
    if (sock_fd == -1)
    {
        return -1;
    }

    //调用connect函数连接服务器
    if (::connect(sock_fd, (struct sockaddr *)&sock_addr, sizeof(struct sockaddr_in)) == -1)
    {
        return -1;
    }

    return sock_fd;
}

#define PRINT_ERRNO(err) printf("ERROR(%-15s %4d):%s\n", #err, err, strerror(err));

int main(int argc, char ** argv)
{
    if (argc != 3)
    {
        std::cout << "Usage:" << argv[0] << " host port" << std::endl;
        return -1;
    }

    PRINT_ERRNO(ECONNREFUSED);
    PRINT_ERRNO(ENETUNREACH);
    PRINT_ERRNO(ETIMEDOUT);

    int i_ret = do_connect(argv[1], atoi(argv[2]));
    if (i_ret == -1)
    {
        std::cout << "RET:" << i_ret << "|ENO:" << errno 
        << "|ERROR:" << strerror(errno) << std::endl;
        
        return -1;
    }
    if (i_ret == -2)
    {
        std::cout << "RET:" << i_ret << "|ERROR:invalid host" << std::endl;
        return -2;
    }
	
    std::cout << "RET:" << i_ret << "|SUCCESS|" << i_ret << std::endl;

    ::close(i_ret);
	
    return 0;
}
1 -- connect对应errno的解析

4.3 connect Function

In the case of a TCP socket, the connect function initiates TCP's three-way handshake (Section 2.6). The function returns only when the connection is established or an error occurs. There are several different error returns possible.

If the client TCP receives no response to its SYN segment, ETIMEDOUT is returned. 4.4BSD, for example, sends one SYN when connect is called, another 6 seconds later, and another 24 seconds later (p. 828 of TCPv2). If no response is received after a total of 75 seconds, the error is returned.

Some systems provide administrative control over this timeout; see Appendix E of TCPv1.

If the server's response to the client's SYN is a reset (RST), this indicates that no process is waiting for connections on the server host at the port specified (i.e., the server process is probably not running). This is a hard error and the error ECONNREFUSED is returned to the client as soon as the RST is received.

An RST is a type of TCP segment that is sent by TCP when something is wrong. Three conditions that generate an RST are: when a SYN arrives for a port that has no listening server (what we just described), when TCP wants to abort an existing connection, and when TCP receives a segment for a connection that does not exist. (TCPv1 [pp. 246–250] contains additional information.)

If the client's SYN elicits an ICMP "destination unreachable" from some intermediate router, this is considered a soft error. The client kernel saves the message but keeps sending SYNs with the same time between each SYN as in the first scenario. If no response is received after some fixed amount of time (75 seconds for 4.4BSD), the saved ICMP error is returned to the process as either EHOSTUNREACH or ENETUNREACH. It is also possible that the remote system is not reachable by any route in the local system's forwarding table, or that the connect call returns without waiting at all.

Many earlier systems, such as 4.2BSD, incorrectly aborted the connection establishment attempt when the ICMP "destination unreachable" was received. This is wrong because this ICMP error can indicate a transient condition. For example, it could be that the condition is caused by a routing problem that will be corrected.

Notice that ENETUNREACH is not listed in Figure A.15, even when the error indicates that the destination network is unreachable. Network unreachables are considered obsolete, and applications should just treat ENETUNREACH and EHOSTUNREACH as the same error.

1 -- 使用Tcpdump观察connect运行状态

对于connect,我们想象下实际使用中会遇到那些状况:

  1. 正常连接一个服务器(连接成功的情况);
  2. 欲连接服务器指定的端口上没有启用监听(服务器可达);
  3. 有路由信息但服务器不存在的情况;
  4. 连接一个路由不可达的服务器;

正常连接一个服务器(连接成功的情况);

2 -- 非阻塞connect原理

connect

3 -- 非阻塞connect(基于select实现)
4 -- 非阻塞connect(基于epoll实现)
原文地址:https://www.cnblogs.com/motadou/p/1918394.html