php tcp udp 通信
程序员文章站
2022-06-06 16:32:50
...
/** * udp收发包 * @param $ip * @param $port * @param $timeout * @return int 0-成功,非0-失败(具体参考类头部错误码常量定义) */ private function udpSocket($ip, $port, $timeout) { $time = microtime(true); $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); if (false === $sock) { return self::UDL_SOCKET_CREATE_FAILED; // socket创建失败 } if (!socket_set_nonblock($sock)) { return self::UDL_SOCKET_SET_NONBLOCK_FAILED; // 设置socket非阻塞失败 } $len = strlen($this->mUdlRequestBuf); if (socket_sendto($sock, $this->mUdlRequestBuf, $len, 0x100, $ip, $port) != $len) { return self::UDL_SOCKET_SEND_FAILED; // socket发送失败 } if (0 == $timeout) { return self::UDL_SUCCESS; // 无回包的情况,返回成功 } $read = array($sock); $second = floor($timeout); $usecond = ($timeout - $second) * 1000000; $ret = socket_select($read, $write, $except, $second, $usecond); if (FALSE === $ret) { return self::UDL_SOCKET_RECEIVE_FAILED; // 收包失败 } elseif ($ret != 1) { return self::UDL_SOCKET_SELECT_TIMEOUT; // 收包超时 } $out = null; while (true) { if (microtime(true) - $time > $timeout) { return self::UDL_SOCKET_TIMEOUT; // 收包超时 } // 32k:32768 = 1024 * 32 $outLen = @socket_recvfrom($sock, $out, 32768, 0, $host, $port); if (!($outLen > 0 && $out != '')) { continue; } $list = unpack('Nseq', substr($out, 9, 4)); $seq = $list['seq']; if ($seq !== $this->mSeq) { continue; } $this->mUdlResponseBuf = $out; return self::UDL_SUCCESS; } } /** * udp收发包 * @param $ip * @param $port * @param $timeout * @return int 0-成功,非0-失败(具体参考类头部错误码常量定义) */ private function tcpSocket($ip, $port, $timeout) { $time = microtime(true); $sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if (false === $sock) { return self::UDL_SOCKET_CREATE_FAILED; // socket创建失败 } if (!socket_connect($sock, $ip, $port)) { return self::UDL_SOCKET_CONNECT_FAILED; } $len = strlen($this->mUdlRequestBuf); if (socket_write($sock, $this->mUdlRequestBuf, $len) != $len) { return self::UDL_SOCKET_SEND_FAILED; } $read = array($sock); $ret = socket_select($read, $write = null, $except = null, $timeout); if (false === $ret) { return self::UDL_SOCKET_RECEIVE_FAILED; } elseif ($ret != 1) { return self::UDL_SOCKET_SELECT_TIMEOUT; } $totalLen = 0; while (true) { if (microtime(true) - $time > $timeout) { return self::UDL_SOCKET_TIMEOUT; // 收包超时 } //读取最多32M的数据 $data = socket_read($sock, self::SOCKET_TCP_MAX_PCK_SIZE, PHP_BINARY_READ); if (empty($data)) { // 已经断开连接 return self::UDL_SOCKET_CLOSED; } else { //第一个包 if ($this->mUdlResponseBuf === null) { $this->mUdlResponseBuf = $data; //在这里从第一个包中获取总包长 $list = unpack('Nlen', substr($data, 1, 4)); $totalLen = $list['len']; } else { $this->mUdlResponseBuf .= $data; } //check if all package is receved if (strlen($this->mUdlResponseBuf) >= $totalLen) { return self::UDL_SUCCESS; } } } } /** * 打包、收发包、解包 * @param $ip * @param $port * @param int $timeout * @return int */ private function sendAndReceive($ip, $port, $timeout = 2, $socketMode) { try { $this->serialize(); if ($socketMode === self::SOCKET_MODE_UDP) { $r = $this->udpSocket($ip, $port, $timeout); } else { $r = $this->tcpSocket($ip, $port, $timeout); } if ($r !== self::UDL_SUCCESS) { return $r; } $this->unserialize(); } catch (Exception $e) { return self::UDL_FAILED; } return self::UDL_SUCCESS; }
上一篇: 简洁的一键SSH脚本