AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / computer / 问题 / 1862793
Accepted
byteflush
byteflush
Asked: 2024-11-26 09:20:49 +0800 CST2024-11-26 09:20:49 +0800 CST 2024-11-26 09:20:49 +0800 CST

为使用持久连接的 API 编写套接字服务器

  • 772

我被要求创建一个应用程序来管理通常位于 NAT 或防火墙后面的设备,因此无法从外部访问。

幸运的是,该设备的创建者想到了这一点,所以他们创建了一个 API,可以连接到外部服务器并保持连接有效,同时还可以通过同一连接接收请求 - 如果我理解手册的话。 有问题的设备是 Videosec 人脸识别设备,协议称为“LAPI”(v1 或 v2),我能找到的有关该协议的所有信息都在这里:http ://videosec.com/support/Firmware/oet/OET-213H_API-JSON.pdf

不幸的是,它不起作用。我一打开设备就收到了心跳请求,但我不知道它是否确认了我的 HTTP 200 响应,而且我发送的任何请求都没有得到满足——只是被设备忽略,并不断发送心跳。

我的问题是 - 我这样做对吗?我是否足够了解 HTTP 保持活动(持久)连接?这是我的服务器套接字代码。它是用 PHP 编写的,但我也尝试过 Python:

<?php
header_remove();
$host = "(public ip)";
$port = 5196;
set_time_limit(0);

if (!extension_loaded('sockets')) {
    die('The sockets extension is not loaded.');
}

$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket\n");
$result = socket_bind($socket, $host, $port) or die("Could not bind to socket\n");
$result = socket_listen($socket, 3) or die("Could not set up socket listener\n");

function getLocalTime()
{
        $dt = new DateTime("now", new DateTimeZone('Europe/Belgrade'));
        return $dt->format('Y-m-d H:i:s');
}

function returnok($spawn, $url = "/LAPI/V1.0/PACS/Controller/HeartReportInfo")
{
        $rsobj = [
                "ResponseURL" => $url,
                "Code" => 0,
                "Data" => [
                        "Time" => getLocalTime()
                ]
        ];
        $resobj = json_encode($rsobj, JSON_UNESCAPED_SLASHES) . PHP_EOL;
        $response = "HTTP/1.1 200 Ok" . PHP_EOL;
        $response.= "Content-Length: " . strlen($resobj) . PHP_EOL;
        $response.= "Content-Type: application/json" . PHP_EOL;
        $response.= "Connection: keep-alive" . PHP_EOL;
        $response.= "X-Frame-Options: SAMEORIGIN" . PHP_EOL;
        $response.= $resobj . PHP_EOL;
        echo $response;
        if (!socket_write($spawn, $response, strlen($response))) {
                echo "Could not write output\n";
        }
}

function writeback($spawn, $url, $method = "GET")
{
        $output = $method . " " . $url . " HTTP/1.1" . PHP_EOL;
        $output.= "Content-Type: application/json" . PHP_EOL;
        $output.= "Connection: keep-alive" . PHP_EOL;
        $output.= PHP_EOL;
        echo $output;
        if (!socket_write($spawn, $output, strlen($output))) {
                echo "Could not write output\n";
        }
}

$spa = true;
while ($spa) {
        $spawn = socket_accept($socket) or die("Could not accept incoming connection\n");
        if ($input = socket_read($spawn, 16 * 1048576)) {
                $input = trim($input);
                if ($spawn) {
                        returnok($spawn);
                        sleep(7);
                        writeback($spawn, "/LAPI/V1.0/PeopleLibraries/BasicInfo");
                } else {
                        $spa = false;
                }
        }
    socket_close($spawn);
}

socket_close($socket);
?>

交换的内容如下:

RECV: POST /LAPI/V1.0/PACS/Controller/HeartReportInfo HTTP/1.1
Host: (redacted):5196
Content-Type: application/json
Content-Length: 180
Connection: keep-alive

{
"RefId": "(redacted)",
"Time": "2011-12-01 00:38:07",
"NextTime": "2011-12-01 00:38:37",
"DeviceCode": "(redacted)",
"DeviceType": 1
}

SEND: HTTP/1.1 200 OK
Content-Length: 108
Content-Type: application/json
Connection: keep-alive
X-Frame-Options: SAMEORIGIN
{"ResponseURL":"/LAPI/V1.0/PACS/Controller/HeartReportInfo","Code":0,"Data":{"Time":"2024-11-26 02:09:06"}}

SEND: GET /LAPI/V1.0/PeopleLibraries/BasicInfo HTTP/1.1
Content-Type: application/json
Connection: keep-alive

RECV: POST /LAPI/V1.0/PACS/Controller/HeartReportInfo HTTP/1.1
Host: (redacted):5196
Content-Type: application/json
Content-Length: 180
Connection: keep-alive

{
"RefId": "(redacted)",
"Time": "2011-12-01 00:38:16",
"NextTime": "2011-12-01 00:38:46",
"DeviceCode": "(redacted)",
"DeviceType": 1
}

SEND: HTTP/1.1 200 OK
Content-Length: 108
Content-Type: application/json
Connection: keep-alive
X-Frame-Options: SAMEORIGIN
{"ResponseURL":"/LAPI/V1.0/PACS/Controller/HeartReportInfo","Code":0,"Data":{"Time":"2024-11-26 02:09:15"}}
php
  • 1 1 个回答
  • 26 Views

1 个回答

  • Voted
  1. Best Answer
    grawity
    2024-11-26T14:51:43+08:002024-11-26T14:51:43+08:00

    通过单个套接字进行双向HTTP 似乎相当不寻常 - 它肯定是 Videosec 的一项超越标准 HTTP“持久连接(保持活动)”的定制发明 - 但是:

    您的请求/响应标头和正文之间缺少一个空行。解析器需要知道标头的结束位置;这由两个连续的换行符表示。例如:

    HTTP/1.1 200 OK
    Content-Length: 108
    Content-Type: application/json
    Connection: keep-alive
    X-Frame-Options: SAMEORIGIN
    
    {"ResponseURL":"/LAPI/V1.0/PACS/Controller/HeartReportInfo","Code":0,"Data":{"Time":"2024-11-26 02:09:15"}}
    

    这甚至适用于没有主体(和/或没有标题)的请求或响应;它们仍然必须以空行结尾。

    (我怀疑您X-Frame-Options:在这里是否需要,因为响应不会发送到 Web 浏览器,因此从这个意义上来说没有“框架”。同样,您的 GET 请求不需要,Content-Type:因为它们没有内容;通常只有响应或 POST 才需要此标头。想要接收JSON 的 GET 将使用Accept:来指示这一点。)

    另外:在这种情况下不要使用PHP_EOL。该常量是特定于平台的,这与您对网络协议的要求完全相反。例如,HTTP 指定使用 CR+LF(\r\n或\x0D\x0A)换行符,无论平台如何(某些服务器恰好接受裸 LF,其他服务器则不接受)。

    • 1

相关问题

  • 我网站上的黑客 php 文件?[关闭]

  • 连接重置后的文件上传结果

  • Apache 两次发送 POST 请求

  • MediaWiki 非主题依赖 CSS

  • 为什么我的 php 文件不能在 xamppp 上运行?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何减少“vmmem”进程的消耗?

    • 11 个回答
  • Marko Smith

    从 Microsoft Stream 下载视频

    • 4 个回答
  • Marko Smith

    Google Chrome DevTools 无法解析 SourceMap:chrome-extension

    • 6 个回答
  • Marko Smith

    Windows 照片查看器因为内存不足而无法运行?

    • 5 个回答
  • Marko Smith

    支持结束后如何激活 WindowsXP?

    • 6 个回答
  • Marko Smith

    远程桌面间歇性冻结

    • 7 个回答
  • Marko Smith

    子网掩码 /32 是什么意思?

    • 6 个回答
  • Marko Smith

    鼠标指针在 Windows 中按下的箭头键上移动?

    • 1 个回答
  • Marko Smith

    VirtualBox 无法以 VERR_NEM_VM_CREATE_FAILED 启动

    • 8 个回答
  • Marko Smith

    应用程序不会出现在 MacBook 的摄像头和麦克风隐私设置中

    • 5 个回答
  • Martin Hope
    Vickel Firefox 不再允许粘贴到 WhatsApp 网页中? 2023-08-18 05:04:35 +0800 CST
  • Martin Hope
    Saaru Lindestøkke 为什么使用 Python 的 tar 库时 tar.xz 文件比 macOS tar 小 15 倍? 2021-03-14 09:37:48 +0800 CST
  • Martin Hope
    CiaranWelsh 如何减少“vmmem”进程的消耗? 2020-06-10 02:06:58 +0800 CST
  • Martin Hope
    Jim Windows 10 搜索未加载,显示空白窗口 2020-02-06 03:28:26 +0800 CST
  • Martin Hope
    andre_ss6 远程桌面间歇性冻结 2019-09-11 12:56:40 +0800 CST
  • Martin Hope
    Riley Carney 为什么在 URL 后面加一个点会删除登录信息? 2019-08-06 10:59:24 +0800 CST
  • Martin Hope
    zdimension 鼠标指针在 Windows 中按下的箭头键上移动? 2019-08-04 06:39:57 +0800 CST
  • Martin Hope
    jonsca 我所有的 Firefox 附加组件突然被禁用了,我该如何重新启用它们? 2019-05-04 17:58:52 +0800 CST
  • Martin Hope
    MCK 是否可以使用文本创建二维码? 2019-04-02 06:32:14 +0800 CST
  • Martin Hope
    SoniEx2 更改 git init 默认分支名称 2019-04-01 06:16:56 +0800 CST

热门标签

windows-10 linux windows microsoft-excel networking ubuntu worksheet-function bash command-line hard-drive

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve