select()有时会阻塞超过提供的超时

时间:2016-05-30 16:18:27

标签: macos sockets bsd

我在非阻塞模式下连接了TCP套接字。发送和接收数据正常工作。接收在专用线程上实现为循环:

    <?php require 'database.php' //<?php include 'session-check-index.php' ?>
<?php include 'authentication.php' ?>
<?php
    session_start();
$follower=$_SESSION['id'];

    $sql = "SELECT * FROM users WHERE username='$username'";
    $result = mysqli_query($database,$sql);
    $rws = mysqli_fetch_array($result);
$following=$rws['id'];

/**
 * this script will auto-follow the user and update their followers count
 * check out your POST data with var_dump($_POST)
**/



if($_POST['action'] == "follow") {

$sql=" INSERT INTO `user_follow` (`follower`, `following`, `subscribed`) VALUES ('$follower', '$following', CURRENT_TIMESTAMP);"
  /**
   * we can pass any action like block, follow, unfollow, send PM....
   * if we get a 'follow' action then we could take the user ID and create a SQL command
   * but with no database, we can simply assume the follow action has been completed and return 'ok'
  **/
   mysqli_query($database,$sql) or die(mysqli_error($database));

}

?>

TCP连接从运行OS X 10.11.5的MacBookPro上通过WiFi连接。当我在建立连接时关闭WiFi时,某些后续fd_set fdset; FD_ZERO(&fdset); FD_SET(internal->m_socket, &fdset); struct timeval timeout; timeout.tv_sec = timeout_ms / 1000; timeout.tv_usec = (timeout_ms % 1000) * 1000; int ret = select(internal->m_socket + 1, &fdset, nullptr, nullptr, &timeout); if (ret == 0) { // handle timeout then loop } else if (ret < 0) { // handle error then abort } else { ret = recv(...); // Read data available on socket then loop } 调用可能需要比指定的超时值更长的时间。

以下是添加日志记录调用的证明(select()IN分别在OUT之前和之后使用传入的超时值和实际测量的已用时间打印:

select()

请注意,没有明显的模式:有时错误似乎不会发生,但大多数情况下都会发生。在关闭超过指定超时的WiFi或之后的一个或多个WiFi后,可以立即进行(WiFi is ON, thread is continuously receiving from socket) 08:31:15 -------- IN = 15000 08:31:30 -------- OUT = 14999 08:31:30 -------- IN = 15000 08:31:45 -------- OUT = 15000 08:31:45 -------- IN = 15000 08:32:00 -------- OUT = 15000 08:32:00 -------- IN = 15000 08:32:15 -------- OUT = 15002 08:32:15 -------- IN = 1000 08:32:15 -------- OUT = 87 <--- data received 08:32:15 -------- IN = 4913 08:32:15 -------- OUT = 0 <--- data received 08:32:15 -------- IN = 15000 (WiFi is turned OFF at this point in the middle of a `select()` call) 08:32:30 -------- OUT = 15004 <--- ok 08:32:30 -------- IN = 1000 08:32:31 -------- OUT = 1003 <--- ok 08:32:31 -------- IN = 1000 08:32:32 -------- OUT = 1006 <--- ok 08:32:32 -------- IN = 1000 08:32:43 -------- OUT = 10999 <--- NOT OK: 10X longer 08:32:43 -------- IN = 1000 08:32:48 -------- OUT = 4965 <--- NOT OK: 5X longer (truncated) 通话。

1 个答案:

答案 0 :(得分:0)

我假设您有一个专门用于运行select循环的线程。将线程放在实时调度类中。以下是来自Apple的示例代码:

#include <mach/mach.h>
#include <mach/mach_time.h>
#include <pthread.h>

void move_pthread_to_realtime_scheduling_class(pthread_t pthread)
{
    mach_timebase_info_data_t timebase_info;
    mach_timebase_info(&timebase_info);

    const uint64_t NANOS_PER_MSEC = 1000000ULL;
    double clock2abs = ((double)timebase_info.denom / (double)timebase_info.numer) * NANOS_PER_MSEC;

    thread_time_constraint_policy_data_t policy;
    policy.period      = 0;
    policy.computation = (uint32_t)(5 * clock2abs); // 5 ms of work
    policy.constraint  = (uint32_t)(10 * clock2abs);
    policy.preemptible = FALSE;

    int kr = thread_policy_set(pthread_mach_thread_np(pthread_self()),
                   THREAD_TIME_CONSTRAINT_POLICY,
                   (thread_policy_t)&policy,
                   THREAD_TIME_CONSTRAINT_POLICY_COUNT);
    if (kr != KERN_SUCCESS) {
        mach_error("thread_policy_set:", kr);
        exit(1);
    }
}

Technical Note TN2169: High Precision Timers in iOS / OS X中阅读更多内容。