如何使用PHP来监听TCP端口? [英] How to listen to a TCP port using PHP?

查看:175
本文介绍了如何使用PHP来监听TCP端口?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个GPS Tracker,通过GPRS连接将数据连接到定义的公共服务器:端口。



我可以定义GPS设备的ip:port



我的问题是,我可以在我的服务器上打开一个端口并监听/保存使用PHP接收到的数据吗?



感谢。

解决方案

编辑/更新2017年8月16日:用户和图书馆作者< @Navarr>评论说,他已经发布了我的原始答案中的代码库的新的更新版本。 github上的新代码链接。随意浏览新的代码,并参考这里的原始示例以获取洞察(我没有亲自探究过/使用过新的代码)。




以下代码将使用此处找到的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) ; //包含文件
$ server = new SocketServer(192.168.1.6,31337); //创建一个服务器绑定到给定的IP地址,并监听端口31337的连接
$ server-> max_clients = 10; //允许不超过10人连接
$ server-> hook(CONNECT,handle_connect); //每次有人连接
$ server-> hook(INPUT,handle_input)时运行handle_connect; //当文本发送到服务器时运行handle_input
$ server-> infinite_loop(); //运行服务器代码,直到进程终止。


函数handle_connect(& $ server,& $ client,$ input)
{
SocketServer :: socket_write_smart($ client-> socket,字符串?,);
}
函数handle_input(& $ server,& $ client,$ input)
{
//你可能想在这里清理你的输入
$ trim = trim($ input); //修剪输入,删除行尾和额外空白。

if(strtolower($ trim)==quit)//用户想要退出服务器
{
SocketServer :: socket_write_smart($ client-> socket, 哦......再见......); //给用户一个悲伤的再见信息,
$ server->断开连接($ client-> server_clients_index); //断开这个客户端。
return; //结束函数
}

$ output = strrev($ trim); //反转字符串

SocketServer :: socket_write_smart($ client-> socket,$ output); //发送客户端返回字符串
SocketServer :: socket_write_smart($ client-> socket,String?,); //请求另一个字符串
}






编辑:为了保持这个答案的相关性和功能,我发现最好不要继续依赖来自外部源的代码,这些代码可能并不总是可用(或者在我的链接中提供的给定URL)。因此,为了方便起见,我在下面添加了与本文顶部链接的SocketServer.class.php文件相对应的代码。 (道歉的长度和可能缺乏缩进/格式化时复制/粘贴,我不是下面的代码的作者)。

 <?php 
/ *! @class SocketServer
@author Navarr Barnier
@abstract使用PHP语言创建多客户端服务器的框架。
* /
类SocketServer
{
/ *! @var config
@abstract Array - 服务器使用的一组配置信息。
* /
保护$ config;

/ *! @var钩住
@abstract数组 - 一个钩子字典和附加到它们的回调函数。
* /
保护$ hooks;

/ *! @var master_socket
@abstract resource - 服务器使用的主套接字。
* /
保护$ master_socket;

/ *! @var max_clients
@abstract unsigned int - 允许连接的最大客户端数量。
* /
public $ max_clients = 10;

/ *! @var max_read
@abstract unsigned int - 一次从套接字读取的最大字节数。
* /
public $ max_read = 1024;

/ *! @var客户端
@abstract Array - 一组连接的客户端。
* /
public $ clients;

/ *! @function __construct
@abstract创建套接字并开始收听。
@param字符串 - 要绑定的IP地址,默认为NULL。
@param int - 绑定到
@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])或die(Issue Binding);
socket_getsockname($ this-> master_socket,$ bind_ip,$ port);
socket_listen($ this-> master_socket);
SocketServer :: debug(在{$ bind_ip}上存在连接:{$ port});
}

/ *! @function hook
@abstract添加一个函数,当某个动作发生时被调用。可以在你的实现中扩展。
@param string - 命令
@param callback-调用函数。
@see unhook
@see trigger_hooks
@result void
* /
公共函数钩子($ 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从某个动作的调用列表中删除一个函数。可以在你的实现中扩展。
@param字符串 - 命令
@param callback-从调用列表中删除的函数
@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运行一次类的动作。
@discussion只能在服务器操作期间运行其他检查时才能使用。否则,使用infinite_loop()
@param void
@see infinite_loop
@result bool - True
* /
public function loop_once()
{
//设置客户端监听读取
$ 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;



设置一个阻塞调用socket_select
if(socket_select($ read,$ write = NULL,$ except = NULL,$ tv_sec = 5)< 1)
{
// SocketServer :: debug(Problem blocking socket_select?);
返回true;
}

//处理新连接
if(in_array($ this-> master_socket,$ read))
{
for($ i = $; $ 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],);
休息;


$ b $ if $($ this $> max_clients-1)
SocketServer :: debug(Too many clients ... :( );
}
}

}

//处理输入
($ i = 0; $ i< $ this - > max_clients; $ i ++)//为每个客户
{
if(isset($ this-> clients [$ i]))
{
if(in_array ($ this-> clients [$ i] - > socket,$ read))
{
$ input = socket_read($ this-> clients [$ i] - > socket,$ ($ input == null)
{
$ this-> disconnect($ i);
}
else $($ this $> max_read);
if b $ b {
SocketServer :: debug({$ i} @ {$ this-> clients [$ i] - > ip} - > {$ input});
$ this-> trigger_hooks(INPUT,$ this-> clients [$ i],$ input);
}
}
}
}
返回true;
}

/ *!@function断开
@abstract断开客户端与服务器的连接
@param int - 断开客户端的索引。
@param string - 消息($ client_index,$ message =)
{
$ i = $ client_index;
SocketServer :: debug(客户端{$ i}来自{$ this-> clients [$ i] - > ip}断开连接);
$ this-> trigger_hooks(DISCONNECT,$ this-> clients [$ i],$ message);
$ this->客户端[$ i] - > destroy();
unset($ this-> clients [$ i]);
}

/ *! @function trigger_hooks
@abstract为特定命令触发挂钩。
@param string - 你想触发钩子的命令。
@param object - 激活此命令的客户端。
@param字符串 - 来自客户端的输入或要发送到钩子的消息。
@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}'为'{$ command}');
$ continue = call_user_func($ function,$ this,$ client,$ input);
if($ continue === FALSE){break; }
}
}
}

/ *! @function infinite_loop
@abstract运行服务器代码,直到服务器关闭。
@see loop_once
@param void
@result void
* /
public function infinite_loop()
{
$ test = true;
do
{
$ test = $ this-> loop_once();
}
while($ test);
}

/ *! @function debug
@static
@abstract直接输出文本。
@discussion是的,应该设法解决这个问题。
@param string - 输出文本
@result void
* /
public static function debug($ text)
{
echo({$文字} \r\\\
);
}

/ *! @function socket_write_smart
@static
@abstract将数据写入套接字,包括数据的长度,除非指定,否则以CRLF结束。
@discussion socket_write_smart返回零表示完全有效,这意味着没有写入字节。万一发生错误,请务必使用===运算符来检查FALSE。
@param resource-套接字实例
@param字符串 - 要写入套接字的数据。
@param string - 数据以结束行。如果您不希望发送行结束,请指定一个。
@result mixed - 返回成功写入套接字的字节数或失败时返回FALSE。错误代码可以通过socket_last_error()来检索。此代码可能会传递给socket_strerror()以获取错误的文本解释。
* /
public static function socket_write_smart(& $ sock,$ string,$ crlf =\r\\\

{
SocketServer :: debug( < - {$ string});
if($ crlf){$ string ={$ string} {$ crlf}; }
返回socket_write($ sock,$ string,strlen($ string));
}

/ *! @function __get
@abstract Magic用于允许读取受保护变量的方法。
@discussion你永远不需要使用这个方法,只需调用$ server->变量就可以了,因为这个方法的存在。
@param string - 要检索$ b $的变量b @result mixed - 返回对所调用变量的引用。
* /
函数& __ get($ name)
{
return $ this-> {$ name};
}
}

/ *! @class SocketServerClient
@author Navarr Barnier
@abstract用于SocketServer的客户端实例
* /
class SocketServerClient
{
/ *! @var socket
@abstract resource - 客户端的套接字资源,用于发送和接收数据。
* /
保护$ socket;

/ *! @var ip
@abstract string - 客户端的IP地址,如服务器所见。
* /
保护$ ip;

/ *! @var主机名
@abstract字符串 - 客户端的主机名,如服务器所示。
@discussion该变量仅在调用lookup_hostname之后设置,因为主机名查找可能占用大量时间。
@see lookup_hostname
* /
protected $ hostname;

/ *! @var server_clients_index
@abstract int - SocketServer客户端阵列中此客户端的索引。
* /
保护$ server_clients_index;

/ *! @function __construct
@param resource-客户端连接的套接字的资源,通常是主套接字。
@param int - 服务器客户端阵列中的索引。
@result void
* /
public function __construct(& $ socket,$ i)
{
$ this-> server_clients_index = $ i;
$ this-> socket = socket_accept($ socket)或者die(Failed to Accept);
SocketServer :: debug(新客户连接);
socket_getpeername($ this-> socket,$ ip);
$ this-> ip = $ ip;
}

/ *! @function lookup_hostname
@abstract搜索用户的主机名并将结果存储到主机名。
@see主机名
@param无效
@result字符串 - 成功时的主机名或失败时的IP地址。
* /
public function lookup_hostname()
{
$ this-> hostname = gethostbyaddr($ this-> ip);
返回$ this->主机名;
}

/ *! @function销毁
@abstract关闭套接字。那差不多。
@param void
@result void
* /
public function destroy()
{
socket_close($ this-> socket);
}

函数& __ get($ name)
{
return $ this-> {$ name};
}

函数__isset($ name)
{
return isset($ this-> {$ name});
}
}


I have a GPS Tracker that connects and send data to a defined public server:port through GPRS connection.

I can define the ip:port of the GPS device

My question is, can I just open a port in my server and listen/save the data received using PHP?

Thanks.

解决方案

Edit/Update Aug. 16, 2017 : User and library author <@Navarr> has commented that he has released a new, updated version of the library the code in my original answer was based from. A link to the new code on his github here. Feel free to explore the new code and refer back to the original example here for insight (I have no personally explored/used the new code).


The below code will use the SocketServer.class.php file found here. It is meant to be run as a standalone process which means under Linux I had to make the file executable, then run it from command line using "php my_server.php". For more information on running php scripts from command line: http://www.funphp.com/?p=33

First grab the SocketServer.class.php file here: http://www.phpclasses.org/browse/file/31975.html

Try this to make use of it, then tweak it to handle receiving your own incoming data as needed. Hope it helps.

<?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
}


Edit: In keeping things relevant and functional for this answer I found it best not to continue to rely on code from an external source that may not always remain available (or at the given URL provided in my link). Therefore, for convenience, I am adding below the code that corresponds to the SocketServer.class.php file I linked to at the top of this post. (Apologies for length and possible lack of indentation/formatting while copy/pasting, I am not the author of the code below).

  <?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});
  }
} 

这篇关于如何使用PHP来监听TCP端口?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆