PHP socket_write故障仅在下一次调用时返回错误

时间:2020-07-31 22:41:16

标签: php sockets tcp arduino iot

我正在尝试通过PHP套接字发送数据,客户端是Arduino设备,当我多次发送数据时,它可以正常接收数据,但是如果我重置客户端(Arduino设备),它会在几秒钟后重新启动,它说它已连接到PHP套接字,然后当我想通过socket_send()重新发送数据时,它默默地失败了,PHP socket_send()并没有在第一个实际错误上返回错误,只是第二次尝试(并且失败),只有这样它才会返回错误(“已发送零字节”)。收到此错误后,我将创建另一个socket_accept()并成功发送消息。

这可能导致什么?我希望它能够正确检测到丢失的连接,以便在需要时可以重新发送数据。

感觉像是将数据发送到旧的连接,并且仅在第二次尝试时才意识到,这可能吗?

可以用socket_select()解决此问题吗?我很难理解它的作用。

说明:如果客户端重新启动并再次连接,则向其发送数据将返回int,然后返回falsefalsefalse(除非我取消设置{{1 }},然后再次执行$accept。如果客户端保持脱机状态,则发送总是返回socket_accept()intintint是发送的字符串的大小。

int

2 个答案:

答案 0 :(得分:1)

我做了一些尝试,并能够重现该问题。这是我的解决方法(也许不是最好的方法,但是可行):

Task

编辑

我想出了一个更简洁的解决方案。我们只是执行@socket_send($accept, $message_to_send, strlen($message_to_send), MSG_EOR); $dataSent = @socket_write($accept, '', 0); if ($dataSent === false) { unset($accept); // ... 函数应该执行的操作。返回socket_sendfalse个接收字节数。

在接收端,您只需解码消息(int)并发回$data中的strlen。客户端也可以验证它是否已收到所有这样的数据。为此,只需将$data['payload']中的strlen$data['payload']进行比较。如果您真的偏执,也可以实施一些校验和。

服务器代码使用$data['length']代替send

socket_send

尽管这行得通,但我认为TCP确实可以做到-确保已接收到数据。也许我们在这里还缺少什么。

答案 1 :(得分:1)

这是我最终使用的,它似乎工作得很好。 它等待来自客户端的答复/确认,如果没有收到确认,message_to_send被保留,连接被清除,在下一个循环中,它将重新连接并重试以发送现有的message_to_send

$total_data_sent = @socket_send($accept, $message_to_send, strlen($message_to_send), MSG_EOR);

// set a timeout for waiting a reply, in this case 500 milliseconds
socket_set_option($accept, SOL_SOCKET, SO_RCVTIMEO, array("sec"=>0, "usec"=>500000));

// read a reply, which should be "ok" (text sent by client)
$reply = socket_read($accept, 1024);

// if reply was not "ok", then unset the connection and will reconnect on next loop
if($reply != "ok"){
    unset($accept);
}

// if reply was "ok", then clear this message as it was successfuly sent
if($reply == "ok"){
    unset($message_to_send);
}