套接字通信的Connect()功能

Connect() functionality of socket communication

关于socket通信的wallclock时间的问题。 我有一个功能,可以找到在中央服务器上注册的服务器。 我正在通过提取服务器的 URL 和端口号并尝试通过表现得像一个简单的 TCP 客户端来连接到它们来为此功能添加一层网络检查。 如果return值大于0,则说明网络正常;如果-1,则网络坏了。

printf("--Checking for network connectivity--\n");
        for(size_t i = 0; i < serverOnNetworkSize; i++) {
           UA_ServerOnNetwork *server = &serverOnNetwork[i];
           A[i] = (char *)UA_malloc(server->discoveryUrl.length+1);
           memcpy(A[i],server->discoveryUrl.data,server->discoveryUrl.length);
           A[i][server->discoveryUrl.length] = 0;
           int length = strlen(A[i]);
          
          //discovery URLs are of the form : opc.tcp://hostname:port
          
          //new addition to extract port
            B[i] = A[i] + 10;
          //printf("Hostname: %s\n", B[i]);
            char *p = strrchr(B[i], ':');
            int port = strtoul(p+1, NULL, 10);
          //printf("%d\n",port);
            B[i][length-5]='[=10=]';
          //printf("Hostname: %s\n", B[i]);
         

         
           //removing the port
           A[i][length-5]='[=10=]';
           //without initial tcp binding
           C[i] = A[i] + 10;
          //printf("Hostname: %s\n", C[i]);

          // FIND IP OF THAT HOST
           if(i!=0){
            char ip_address[50];

            find_ip_address(C[i],ip_address);  
            socketCommunication(ip_address,C[i],port);
       }
}
          printf("--Checks done!--\n");

全局函数:

int find_ip_address(char *hostname, char *ip_address)
{
      struct hostent *host_name;
      struct in_addr **ipaddress;
      int count;
      if((host_name = gethostbyname(hostname)) == NULL)
      {
            herror("\nIP Address Not Found\n");
            return 1;
      }
      else
      {
            ipaddress = (struct in_addr **) host_name->h_addr_list;
            for(count = 0; ipaddress[count] != NULL; count++)
            {
                  strcpy(ip_address, inet_ntoa(*ipaddress[count]));
                  return 0;
            }
      }
      return 1;
}

void socketCommunication(char *ip_address,char *hostname, int port){
     int clientSocket,ret;
    struct  sockaddr_in serverAddr;
    char buffer[1024];
 
    
    clientSocket = socket(AF_INET,SOCK_STREAM,0);
    if(clientSocket<0){
        printf("Error in connection \n");
        exit(1);
    }

    //printf("Client socket is created\n");

    memset(&serverAddr,'[=11=]',sizeof(serverAddr));

    serverAddr.sin_port = htons(port);
    serverAddr.sin_family=AF_INET;
    
    serverAddr.sin_addr.s_addr=inet_addr(ip_address);

    ret = connect(clientSocket,(struct sockaddr*)&serverAddr,sizeof(serverAddr));
    if(ret<0){
        printf("\nLOOKS LIKE NETWORK CONNECTION HAS FAILED. HAVE A LOOK AT    THE NETWORK CONNECTIVITY at host : %s\n",hostname);
        printf("\n----Updated Status Information----:\n");
        printf("Discovery URL : opc.tcp://%s:%d\n",hostname,port);
        printf("Status:CONNECTON TIMED OUT\n");
        printf("\n");
   }

为了对此进行测试,我关闭了其中一台注册服务器的网络。 当我测量时间时,它显示 18 秒、24、38 秒等不一致的值

这些值在我切换服务器网络和 运行 我的应用程序时出现。在同一应用程序的第二个 运行 上,该值有时会减少到 2 秒或 1 秒。

输出:


LOOKS LIKE NETWORK CONNECTION HAS FAILED. HAVE A LOOK AT THE NETWORK CONNECTIVITY at host : o755-gksr

----Updated Status Information----:
Discovery URL : opc.tcp://o755-gksr:4841
Status:CONNECTON TIMED OUT

--Checks done!--
Time measured: 18 seconds.


再试一次输出

--Checking for network connectivity--

LOOKS LIKE NETWORK CONNECTION HAS FAILED. HAVE A LOOK AT THE NETWORK CONNECTIVITY at host : o755-gksr

----Updated Status Information----:
Discovery URL : opc.tcp://o755-gksr:4841
Status:CONNECTON TIMED OUT

--Checks done!--
Time measured: 0 seconds.

我的问题是:为什么会显示不一致的值?如果无法连接,是否应该 return -1 并快速显示错误? 是否有任何后台进程在停止之前尝试建立有限次数的连接?

请告诉我。

此致, 洛山

connect() 行为及其超时在很大程度上取决于底层网络。目标机器宕机时 connect() 失败的原因还有很多。大多数情况下的错误是:

  • ETIMEDOUT - 这意味着客户端发送了 SYN,但它根本没有收到任何响应。这是一个 TCP 超时,可能会很长(分钟)。
  • EHOSTUNREACH - 这意味着本地 ARP 查询失败或客户端发送 SYN 和 ICMP 错误收到主机无法访问。几秒钟后检测到 ARP 查询失败。 ICMP 错误 Host Unreachable 通常由远程路由器在其 ARP 查询失败时返回。

那么,如果服务器与您的客户端位于同一网络中,您的情况会怎样:

  • 客户端的 ARP 缓存中有服务器的 MAC 地址。
  • 您“从其中一个注册服务器关闭网络。”。您可能从服务器或类似设备上断开电缆。
  • 客户端调用connect。 SYN 直接从 ARP 缓存发送到 MAC 地址,最坏的情况是两分钟后使用 ETIMEDOUT 连接 returns。
  • 客户端删除 ARP 缓存中的条目。
  • 后续连接需要ARP解析。它要么在 3 个 ARP 请求(3 秒)后失败,要么在 ARP 缓存中的否定条目有效时立即失败。它可能只在几秒钟内有效。

如果服务器在远程网络中,则情况类似。在这种情况下,远程路由器的 ARP 缓存是有罪的。如果远程路由器无法将 IP 地址解析为 MAC 地址,则它几乎立即发送 ICMP 主机无法访问,但如果远程路由器在其 ARP 缓存中仍有目标 IP,则需要一些时间才能意识到缓存条目已过时,并且MAC 地址不可用。