Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux套接字超时在WSL上有效,但在Ubuntu上无效_Linux_Sockets_Timeout_Windows Subsystem For Linux - Fatal编程技术网

Linux套接字超时在WSL上有效,但在Ubuntu上无效

Linux套接字超时在WSL上有效,但在Ubuntu上无效,linux,sockets,timeout,windows-subsystem-for-linux,Linux,Sockets,Timeout,Windows Subsystem For Linux,我尝试在没有服务器的情况下运行TCP客户端。这个想法只是周期性地尝试联系。 为此,客户端尝试连接到本地主机上的端口1500 一段代码: // Create socket if ((create_socket=socket (AF_INET, SOCK_STREAM, PF_UNSPEC)) > 0) printf ("Socket created\n"); address.sin_family = AF_INET; addre

我尝试在没有服务器的情况下运行TCP客户端。这个想法只是周期性地尝试联系。 为此,客户端尝试连接到本地主机上的端口1500

一段代码:

    // Create socket
    if ((create_socket=socket (AF_INET, SOCK_STREAM, PF_UNSPEC)) > 0)
      printf ("Socket created\n");
    address.sin_family = AF_INET;
    address.sin_port = htons (1500);
    inet_aton (argv[1], &address.sin_addr);

    // Connect to server
    connect ( create_socket,
                    (struct sockaddr *) &address,
                    sizeof (address));

    FD_ZERO(&fdset);
    FD_SET(create_socket, &fdset);
    tv.tv_sec = 2;             /* 2 seconds timeout */
    tv.tv_usec = 0;

    rv = select(create_socket + 1, NULL, &fdset, NULL, &tv);
    if (rv == 1)
    {
        int so_error;
        socklen_t len = sizeof so_error;

        getsockopt(create_socket, SOL_SOCKET, SO_ERROR, &so_error, &len);

        if (so_error == 0)
        {
          printf ("Connection with server (%s) established \n",
          inet_ntoa (address.sin_addr));
        }
        else
        {
          printf("Error on connect: unsuccessfull\n");
          close (create_socket);
          continue;
        }
    }
    else if (rv == 0)
    {
      printf("Timeout on connect\n");
      close (create_socket);
      continue;
    }
    else
    {
      printf("Error on connect\n");
      close (create_socket);
      continue;
    }
我在WSL上的Ubuntu18.04中设置了它。在那里,代码等待
select
,等待定义的超时2秒,并返回相应的返回值。(超时时为0,连接时为1)。 在WSL和VMware上,
connect
的返回值为-1。 在Ubuntu 18(VMware)中,这一行没有停顿。在任何情况下,即使没有任何服务器侦听该端口,我也会立即得到返回值1

为什么会有这种差异

该代码后面也有类似的行为:

    tv.tv_sec = 2;
    tv.tv_usec = 0;
    if (setsockopt(create_socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv) < 0)
    {
      printf("Error on setsockopt SO_RCVTIMEO");
      exit(EXIT_FAILURE);
    }
    // INNER LOOP: Receive data
    do
    {
      size = recv(create_socket, buffer, BUF-1, 0);
      if( size > 0)
      {
        buffer[size] = '\0';
        printf ("Message received: %s\n", buffer);
      }
      else if (size == -1)
      {
      // on VMware, errno is 107 if there is no server, but coming to that line was not intended
        printf ("Timeout\n");
      }
      else //
      {
        printf("Server offline\n");
        // GO BACK TO OUTER LOOP and reconnect
        break;
      }
在WSL中,输出是

Socket created
Connect. rv = -1
errno = 111 (ECONNREFUSED)
然后2秒钟内什么都没有 后来

Timeout on connect
Socket created
Connect. rv = -1
errno = 111 (ECONNREFUSED)
2秒钟内又一次什么都没有

VMware中的输出

Socket created
Connect. rv = -1
errno = 111 (ECONNREFUSED)
Connection with server (127.0.0.1) established 
Timeout
Timeout
Timeout
Timeout
没有超时的情况下


超时的想法是尝试定期连接,但不是尽可能快。

显然,当
errno=111(econnreference)
之后建立与服务器(127.0.0.1)的连接时,出现了一些问题。

connect
返回
-1
并且
errno
不是
EINPROGRESS
时,您应该使用
选择
getsockopt(…SO_ERROR…
)。根据,这仅为
EINPROGRESS
记录

在真正的Linux和WSL上,在连接失败后,您会得到
errno=111(econnreference)
。我认为WSL的超时是错误的(已被拒绝),所以等待结果是没有意义的。但是由于没有指定行为,它可能依赖于实现

如果您想在下一次连接尝试之前有一个延迟,则不应使用
select
,而应使用
sleep
,然后重复循环

我建议这样做:

    rv = connect ( create_socket,
                    (struct sockaddr *) &address,
                    sizeof (address));

    printf ("Connect. rv = %i\n", rv);

    if (rv == -1)
    {
      switch (errno)
      {
        case ECONNREFUSED:  printf ("errno = %i (ECONNREFUSED) %s\n", errno, strerror(errno)); break;
        default:  printf ("errno = %i (other) %s\n", errno, strerror(errno)); break;
      }
      if(errno != EINPROGRESS)
      {
        sleep(10); // chose a suitable delay before next connection attempt
        continue;
      }
    }


fcntl
with
F_GETFL
返回WSL和VMware的当前标志“2”。请回答您的问题并添加更多详细信息:澄清“适当的返回值”。您得到的返回值是多少?如果select指示文件描述符,则表示请求的文件描述符操作不应阻塞。这也意味着操作将立即返回错误或EOF条件。您应该检查
connect
的返回值。“在VMware中,我直接获得反馈”是否有可接收的数据?你到底得到了什么反馈?在
size==-1
的情况下,您应该选中
errno
。请将所有信息添加到问题中,而不是作为评论。@Bodo:谢谢。按要求更新问题。我们无法完全检查或运行不完整的代码。我建议创建一个。解释前提条件并显示不同情况下程序的输出也可能有助于理解发生了什么。如果
connect
的返回值为-1,则还应选中
errno
。也许此时您已经得到了
errno==econnrefered
或其他。根据手册页,
select
用于写入和读取
SO\u ERROR
的行为仅为
errno==EINPROGRESS
定义。当没有服务器在侦听时,RST数据包将主动拒绝连接,因此这通常是快速的。
    rv = connect ( create_socket,
                    (struct sockaddr *) &address,
                    sizeof (address));

    printf ("Connect. rv = %i\n", rv);

    if (rv == -1)
    {
      switch (errno)
      {
        case ECONNREFUSED:  printf ("errno = %i (ECONNREFUSED) %s\n", errno, strerror(errno)); break;
        default:  printf ("errno = %i (other) %s\n", errno, strerror(errno)); break;
      }
      if(errno != EINPROGRESS)
      {
        sleep(10); // chose a suitable delay before next connection attempt
        continue;
      }
    }