如何使用 PHP 监听 TCP 端口? [关闭]
Posted
技术标签:
【中文标题】如何使用 PHP 监听 TCP 端口? [关闭]【英文标题】:How to listen to a TCP port using PHP? [closed] 【发布时间】:2012-10-14 19:01:32 【问题描述】:我有一个 GPS 追踪器,它通过 GPRS 连接连接并将数据发送到定义的公共服务器:端口。
我可以定义 GPS 设备的 ip:port
我的问题是,我可以在我的服务器中打开一个端口并监听/保存使用 php 接收到的数据吗?
谢谢。
【问题讨论】:
php.net/manual/en/function.socket-listen.php? GPS 追踪器的品牌和型号是什么?大多数我知道也支持 HTTP GET 是什么阻碍了您尝试一下?您遇到了哪个具体错误? @Baba 是通用品牌,型号为TK102 @hakre 我的限制更多是关于服务器,php 可以在关闭端口的服务器中创建套接字吗? 【参考方案1】:2017 年 8 月 16 日编辑/更新: 用户和库作者 评论说,他已经发布了一个新的更新版本的库,我的原始答案中的代码是基于该版本的。 new code on his github here 的链接。随意探索新代码并参考此处的原始示例以获得洞察力(我没有亲自探索/使用过新代码)。
以下代码将使用此处找到的 SocketServer.class.php 文件。它旨在作为独立进程运行,这意味着在 Linux 下我必须使文件可执行,然后使用“php my_server.php”从命令行运行它。 有关从命令行运行 php 脚本的更多信息: http://www.funphp.com/?p=33
首先在此处获取 SocketServer.class.php 文件: http://www.phpclasses.org/browse/file/31975.html
尝试使用它,然后根据需要调整它以处理接收您自己的传入数据。希望对您有所帮助。
<?php
require_once("SocketServer.class.php"); // Include the File
$server = new SocketServer("192.168.1.6",31337); // Create a Server binding to the given ip address and listen to port 31337 for connections
$server->max_clients = 10; // Allow no more than 10 people to connect at a time
$server->hook("CONNECT","handle_connect"); // Run handle_connect every time someone connects
$server->hook("INPUT","handle_input"); // Run handle_input whenever text is sent to the server
$server->infinite_loop(); // Run Server Code Until Process is terminated.
function handle_connect(&$server,&$client,$input)
SocketServer::socket_write_smart($client->socket,"String? ","");
function handle_input(&$server,&$client,$input)
// You probably want to sanitize your inputs here
$trim = trim($input); // Trim the input, Remove Line Endings and Extra Whitespace.
if(strtolower($trim) == "quit") // User Wants to quit the server
SocketServer::socket_write_smart($client->socket,"Oh... Goodbye..."); // Give the user a sad goodbye message, meany!
$server->disconnect($client->server_clients_index); // Disconnect this client.
return; // Ends the function
$output = strrev($trim); // Reverse the String
SocketServer::socket_write_smart($client->socket,$output); // Send the Client back the String
SocketServer::socket_write_smart($client->socket,"String? ",""); // Request Another String
编辑:为了保持这个答案的相关性和功能性,我发现最好不要继续依赖可能并不总是可用的外部源代码(或在我的链接中提供的给定 URL)。因此,为方便起见,我在下面添加了与本文顶部链接到的 SocketServer.class.php 文件相对应的代码。 (对于复制/粘贴时可能缺少缩进/格式,我深表歉意,我不是下面代码的作者)。
<?php
/*! @class SocketServer
@author Navarr Barnier
@abstract A Framework for creating a multi-client server using the PHP language.
*/
class SocketServer
/*! @var config
@abstract Array - an array of configuration information used by the server.
*/
protected $config;
/*! @var hooks
@abstract Array - a dictionary of hooks and the callbacks attached to them.
*/
protected $hooks;
/*! @var master_socket
@abstract resource - The master socket used by the server.
*/
protected $master_socket;
/*! @var max_clients
@abstract unsigned int - The maximum number of clients allowed to connect.
*/
public $max_clients = 10;
/*! @var max_read
@abstract unsigned int - The maximum number of bytes to read from a socket at a single time.
*/
public $max_read = 1024;
/*! @var clients
@abstract Array - an array of connected clients.
*/
public $clients;
/*! @function __construct
@abstract Creates the socket and starts listening to it.
@param string - IP Address to bind to, NULL for default.
@param int - Port to bind to
@result void
*/
public function __construct($bind_ip,$port)
set_time_limit(0);
$this->hooks = array();
$this->config["ip"] = $bind_ip;
$this->config["port"] = $port;
$this->master_socket = socket_create(AF_INET, SOCK_STREAM, 0);
socket_bind($this->master_socket,$this->config["ip"],$this->config["port"]) or die("Issue Binding");
socket_getsockname($this->master_socket,$bind_ip,$port);
socket_listen($this->master_socket);
SocketServer::debug("Listenting for connections on $bind_ip:$port");
/*! @function hook
@abstract Adds a function to be called whenever a certain action happens. Can be extended in your implementation.
@param string - Command
@param callback- Function to Call.
@see unhook
@see trigger_hooks
@result void
*/
public function hook($command,$function)
$command = strtoupper($command);
if(!isset($this->hooks[$command])) $this->hooks[$command] = array();
$k = array_search($function,$this->hooks[$command]);
if($k === FALSE)
$this->hooks[$command][] = $function;
/*! @function unhook
@abstract Deletes a function from the call list for a certain action. Can be extended in your implementation.
@param string - Command
@param callback- Function to Delete from Call List
@see hook
@see trigger_hooks
@result void
*/
public function unhook($command = NULL,$function)
$command = strtoupper($command);
if($command !== NULL)
$k = array_search($function,$this->hooks[$command]);
if($k !== FALSE)
unset($this->hooks[$command][$k]);
else
$k = array_search($this->user_funcs,$function);
if($k !== FALSE)
unset($this->user_funcs[$k]);
/*! @function loop_once
@abstract Runs the class's actions once.
@discussion Should only be used if you want to run additional checks during server operation. Otherwise, use infinite_loop()
@param void
@see infinite_loop
@result bool - True
*/
public function loop_once()
// Setup Clients Listen Socket For Reading
$read[0] = $this->master_socket;
for($i = 0; $i < $this->max_clients; $i++)
if(isset($this->clients[$i]))
$read[$i + 1] = $this->clients[$i]->socket;
// Set up a blocking call to socket_select
if(socket_select($read,$write = NULL, $except = NULL, $tv_sec = 5) < 1)
// SocketServer::debug("Problem blocking socket_select?");
return true;
// Handle new Connections
if(in_array($this->master_socket, $read))
for($i = 0; $i < $this->max_clients; $i++)
if(empty($this->clients[$i]))
$temp_sock = $this->master_socket;
$this->clients[$i] = new SocketServerClient($this->master_socket,$i);
$this->trigger_hooks("CONNECT",$this->clients[$i],"");
break;
elseif($i == ($this->max_clients-1))
SocketServer::debug("Too many clients... :( ");
// Handle Input
for($i = 0; $i < $this->max_clients; $i++) // for each client
if(isset($this->clients[$i]))
if(in_array($this->clients[$i]->socket, $read))
$input = socket_read($this->clients[$i]->socket, $this->max_read);
if($input == null)
$this->disconnect($i);
else
SocketServer::debug("$i@$this->clients[$i]->ip --> $input");
$this->trigger_hooks("INPUT",$this->clients[$i],$input);
return true;
/*! @function disconnect
@abstract Disconnects a client from the server.
@param int - Index of the client to disconnect.
@param string - Message to send to the hooks
@result void
*/
public function disconnect($client_index,$message = "")
$i = $client_index;
SocketServer::debug("Client $i from $this->clients[$i]->ip Disconnecting");
$this->trigger_hooks("DISCONNECT",$this->clients[$i],$message);
$this->clients[$i]->destroy();
unset($this->clients[$i]);
/*! @function trigger_hooks
@abstract Triggers Hooks for a certain command.
@param string - Command who's hooks you want to trigger.
@param object - The client who activated this command.
@param string - The input from the client, or a message to be sent to the hooks.
@result void
*/
public function trigger_hooks($command,&$client,$input)
if(isset($this->hooks[$command]))
foreach($this->hooks[$command] as $function)
SocketServer::debug("Triggering Hook '$function' for '$command'");
$continue = call_user_func($function,$this,$client,$input);
if($continue === FALSE) break;
/*! @function infinite_loop
@abstract Runs the server code until the server is shut down.
@see loop_once
@param void
@result void
*/
public function infinite_loop()
$test = true;
do
$test = $this->loop_once();
while($test);
/*! @function debug
@static
@abstract Outputs Text directly.
@discussion Yeah, should probably make a way to turn this off.
@param string - Text to Output
@result void
*/
public static function debug($text)
echo("$text\r\n");
/*! @function socket_write_smart
@static
@abstract Writes data to the socket, including the length of the data, and ends it with a CRLF unless specified.
@discussion It is perfectly valid for socket_write_smart to return zero which means no bytes have been written. Be sure to use the === operator to check for FALSE in case of an error.
@param resource- Socket Instance
@param string - Data to write to the socket.
@param string - Data to end the line with. Specify a "" if you don't want a line end sent.
@result mixed - Returns the number of bytes successfully written to the socket or FALSE on failure. The error code can be retrieved with socket_last_error(). This code may be passed to socket_strerror() to get a textual explanation of the error.
*/
public static function socket_write_smart(&$sock,$string,$crlf = "\r\n")
SocketServer::debug("<-- $string");
if($crlf) $string = "$string$crlf";
return socket_write($sock,$string,strlen($string));
/*! @function __get
@abstract Magic Method used for allowing the reading of protected variables.
@discussion You never need to use this method, simply calling $server->variable works because of this method's existence.
@param string - Variable to retrieve
@result mixed - Returns the reference to the variable called.
*/
function &__get($name)
return $this->$name;
/*! @class SocketServerClient
@author Navarr Barnier
@abstract A Client Instance for use with SocketServer
*/
class SocketServerClient
/*! @var socket
@abstract resource - The client's socket resource, for sending and receiving data with.
*/
protected $socket;
/*! @var ip
@abstract string - The client's IP address, as seen by the server.
*/
protected $ip;
/*! @var hostname
@abstract string - The client's hostname, as seen by the server.
@discussion This variable is only set after calling lookup_hostname, as hostname lookups can take up a decent amount of time.
@see lookup_hostname
*/
protected $hostname;
/*! @var server_clients_index
@abstract int - The index of this client in the SocketServer's client array.
*/
protected $server_clients_index;
/*! @function __construct
@param resource- The resource of the socket the client is connecting by, generally the master socket.
@param int - The Index in the Server's client array.
@result void
*/
public function __construct(&$socket,$i)
$this->server_clients_index = $i;
$this->socket = socket_accept($socket) or die("Failed to Accept");
SocketServer::debug("New Client Connected");
socket_getpeername($this->socket,$ip);
$this->ip = $ip;
/*! @function lookup_hostname
@abstract Searches for the user's hostname and stores the result to hostname.
@see hostname
@param void
@result string - The hostname on success or the IP address on failure.
*/
public function lookup_hostname()
$this->hostname = gethostbyaddr($this->ip);
return $this->hostname;
/*! @function destroy
@abstract Closes the socket. Thats pretty much it.
@param void
@result void
*/
public function destroy()
socket_close($this->socket);
function &__get($name)
return $this->$name;
function __isset($name)
return isset($this->$name);
【讨论】:
这个脚本必须在同一个服务器上运行,对吧? 是的。我在我的 Linux 服务器上运行它。将此脚本放在一个名为“my_server.php”的文件中,并将其与 SocketServer.class.php 一起放入它们自己的文件夹中。切换到该目录,使文件可执行(“chmod a+x my_server.php”)并从命令行运行“php my_server.php”。 好的,试过了。收到错误“无法绑定地址。地址已在使用中”。这是什么意思? 这一行:$server = new SocketServer("192.168.1.6",31337);您想在此处更改 ip-address 以反映服务器的 ip-address。这恰好是我当时的情况。端口号 (31337) 是任意的,可以是您真正想要的任何东西。如果您在 Linux 上运行“ifconfig”并记下服务器的地址,然后将其插入并尝试一下。 太好了,我更改了端口号,它可以工作了。我将尝试将 GPS 重定向到我的地址【参考方案2】:是的,使用 socket_create
、socket_bind
、socket_listen
和 socket_accept
http://www.php.net/manual/en/function.socket-create.php
http://www.php.net/manual/en/function.socket-bind.php
http://www.php.net/manual/en/function.socket-listen.php
http://www.php.net/manual/en/function.socket-accept.php
这些页面上有很多关于如何使用它们的示例。
【讨论】:
服务器是否有任何动作?打开一个端口? 是的,您可以通过socket_bind
调用来指定。【参考方案3】:
是的,PHP 专门为此提供了一个 socket_listen() 函数。 http://php.net/manual/en/function.socket-listen.php。
【讨论】:
以上是关于如何使用 PHP 监听 TCP 端口? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章