首页 > 解决方案 > 套接字通信的 Connect() 功能

问题描述

关于so​​cket通信挂钟时间的问题。我有一个功能,可以找到在中央服务器上注册的服务器。我通过提取服务器的 URL 和端口号并尝试通过表现得像一个简单的 TCP 客户端来连接到它们,从而在此功能上添加一层网络检查。如果返回值大于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]='\0';
          //printf("Hostname: %s\n", B[i]);
         

         
           //removing the port
           A[i][length-5]='\0';
           //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,'\0',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.

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

请告诉我。

问候, 罗山

标签: csocketstcpclient-server

解决方案


connect()行为及其超时高度依赖于底层网络。connect()目标机器停机时失败的原因还有很多。大多数情况下的错误是:

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

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

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

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


推荐阅读