Swoole+redis implementation of real-time data push

Source: Internet
Author: User
Tags auth documentation php error redis set time switches

# # Swoole+redis Implementation of real-time data push

<?php/** * *************************************** * Single Process protection * * *************************
* * $phpSelf = Realpath ($_server[' php_self ')); $lockFile = $phpSelf.
Lock ';
$lockFileHandle = fopen ($lockFile, "w"); if ($lockFileHandle = = False) {exit ("Can not create lock file $lockFile \ n");} if (!flock ($lockFileHandle, LOCK_EX + LOC K_NB)) {Exit (date ("Y-m-d h:i:s"). "
Process already exist.\n "); /** * *************************************** * Enter the program, define the relevant configuration * * *************************************
* * * */set_time_limit (0);
Timeout for the socket session, set by the business scenario setting, set to never timeout//If set time, the => transfer from the socket => the entire process must be completed within the defined time, otherwise the socket is automatically closed and thrown warning
Ini_set (' Default_socket_timeout ',-1); $conf = Array (' Listen ' => array (' Host ' => ' 0.0.0.0 ', ' Port ' => ' 8008 '), ' setting ' => Array (//program maximum number of connections allowed, Used to set the maximum number of TCP connections that can be maintained by the server, after which the new connection is rejected, defaults to the Ulimit-n value, and if the setting is greater than ulimit-n the force is reset to Ulimit-n, and if you do need to set a value exceeding Ulimit-n, modify the system value Vim/etc/security/limits.conf modifies Nofile's value "Max_conn" => 1024,//Enable CPU affinity settings (enabled for full asynchronous non-blocking), enabling this attribute on a multi-core server binds Swoole reactor thread/worker process to a fixed nucleus. You can avoid process/thread runtime switching between multiple cores, increasing CPU cache hit ratio, how to determine which kernel is bound to, refer to the documentation, view the command: Taskset-p process id ' open_cpu_affinity ' => 0,//configure TAS K process number, which will enable the task feature when this parameter is configured. So server must register Ontask, ONFINISH2 event callback functions. If you do not register, the server program will not start.
		The task process is blocked synchronously and is configured in the same way as the worker synchronization mode. ' Task_worker_num ' => 20,//Set the maximum number of tasks for the task process. A task process will automatically exit after it has finished processing tasks that exceed this number. This parameter is designed to prevent PHP process memory from overflowing. If you do not want the process to automatically exit can be set to 0, the default is 0 ' task_max_request ' => 1024,//Set the data temp directory for the task, in Swoole_server, if the posted data exceeds 8192 bytes, temporary files will be enabled to save the data.
		This is where the task_tmpdir is used to set the temporary file save. ' Task_tmpdir ' => '/tmp/', the number of//worker processes, adjusted according to the pattern of business code, full asynchronous non-blocking can be set to 1-4 times the number of CPU cores; synchronization blocking, please refer to the documentation adjustment ' Worker_num ' => 8,/= Fixed swoole error log file ' log_file ' => '/tmp/log/log.txt ',//ssl the location of the public key and private key, enabling WSS must add swoole option '--enable-openssl when compiling Ssl_cert_

File ' => '/usr/local/nginx/conf/server.cer ', ' ssl_key_file ' => '/usr/local/nginx/conf/server.key ',); /**
 * ********************** Initialize REDIS Connection * * ***************************************/$redis = null;
$redis = new Redis ();
$redis->connect (Redis_host, Redis_port);
$redis->auth (REDIS_PWD);

$GLOBALS [' Redis ']= $redis; /** * *************************************** * When the script restarts, erase historical data * * *************************************** *
/$sArr = $redis->smembers (redis_s_key);
		if (!empty ($SARR)) {foreach ((array) $sArr as $key => $sc) {$fdArr = $redis->smembers (redis_s_fd. $SC);
		foreach (array) $fdArr as $k => $fd) {$res 1 = $redis->del (redis_fd_s. $fd);
	$res 2 = $redis->del (redis_s_fd. $SC);
} $redis->del (Redis_s_key);

} $redis->del (Redis_zs_key); /** * *************************************** * Binding Callback Event * * ***********************************
* * $ws = NULL; WSS Service $WS = new Swoole_websocket_server ($conf [' Listen '] [' host '], $conf [' Listen '] [' Port '], swoole_process, Swoole_ sock_tcp |
SWOOLE_SSL);$ws->set ($conf [' setting ']); 
 /** * Server initiates callback to this function on main thread of master process * Before this event Swoole server has already created the manager process * has created a worker subprocess * has been listening on all TCP/UDP ports * has tapped the timer * A global resource object created in OnStart cannot be used in a worker process because the worker process has already been created when the onstart call occurs. The newly created object is in the main process and the worker process is unable to access this memory area. Therefore, the code created by the global object needs to be placed before Swoole_server_start/$ws->on (' Start ', function ($WS) {swoole_set_process_name (process_name. ').
_master ');

}); /** * and OnStart callback functions that execute in parallel in different processes (no sequential) * @param: $ws swoole_websocket_server Object * @param: $wid The ID assigned when the process was created ( Not process ID) * Note point: * 1. This event occurs when the worker process/task process starts. Onworkerstart/onstart are executed concurrently, without sequencing, the objects created here can be used within the process lifecycle * 2. After swoole1.6.11, the Onworkerstart is also triggered in task_worker, so in the following processing, it is added to determine whether the business type $jobtype is a task or a work, and if it is a task, it is named ****_tasker_$id. If it is a Worker, it is named ****_worker_$id * 3. The worker/task process exits when a PHP fatal error occurs or when the code actively calls exit, and the management process will re-create the new process * 5. If you want to use Swoole_server_reload to implement code overload entry, you must require your business file in Workerstart instead of the file header.
 The files that were included before the Onworkerstart call will not be loaded back into the code. * 6. You can place a common, immutable php file before Onworkerstart (for example, the Redis configuration above). This does not overload the code, but all WThe Orker is shared and does not require additional memory to hold the data. * 7.  Code after onworkerstart each worker needs to keep a copy of the */$ws->on in memory (' Workerstart ', function ($ws, $wid) {$jobType = $ws->taskworker ?
	' Tasker ': ' Worker '; Swoole_set_process_name (process_name. ') _ '. $jobType. '
	_ '. $wid); $GLOBALS [' ws '] = $WS; Save the server object to the global for use if ($jobType = = ' worker ') {//Bind the Redis subscription process to a worker process if ($wid = = 0) {$dataRedis = n
            ull;
            $dataRedis = new Redis ();
            $dataRedis->connect (Redis_host_data, redis_port_data);
            $dataRedis->auth (Redis_pwd_data); Use Psubscribe to subscribe to a channel of the specified mode, where * means all channels//Please note that Redis subscriptions do not provide a differentiated library (DB) feature, so multiple libraries are also subscribed to the $dataRedis-&GT;PSU when they publish the same name channel
		Bscribe (Array ("*"), "Sendtask");

}
	}
}); /** * Management process enabled, call this callback function * Note the manager process cannot add timers * The SendMessage interface can be invoked to send messages to other worker processes in the manager process/$ws->on (' Managerstart ', fun Ction ($WS) {swoole_set_process_name (process_name.)
_manage ');

}); /** * Swoole websocket Service-specific callback function that must be defined in the WebSocket server, otherwise the WebSocket service will not start * when the serverThis function is called back when a data frame from the client is received * @param: $ws is a Swoole_websocket_server object whose structure can be var_dump to view * @param when debugging: $frame for swoole_websocket_ The Frame object, which contains the data frame information sent by the client, contains the following four properties: * @param: $frame-&GT;FD: The client's socket ID, each ID corresponds to a client, and when the message is pushed, it needs to be specified * @param: $frame-> Data: Content can be text content or binary data (pictures, etc.), can be judged by the value of opcode. $data if it is a text type, the encoding format must be UTF-8, which is the @param of the WebSocket protocol: $frame The opcode type of the->opcode:websocket, you can refer to the WebSocket Protocol standard document, Websocket_opcode_text = 0x1, text data; Websocket_opcode_binary = 0x2, binary data * @param: $frame->finish: Indicates whether the data frame is complete, a WEBSOCKET request may be sent into multiple data frames * NOTE: Pin sent by client
    G frame will not trigger onmessage, the bottom will automatically reply Pong package/$ws->on (' message ', function ($ws, $frame) {echo "Server has receive message\n";
Receive the client request, and after establishing the connection, carries on the corresponding business processing handleclientdata ($WS, $frame);

}); /** * is invoked within the task_worker process. The worker process can use the Swoole_server_task function to post a new task to the Task_worker process (using taskwait here) * The current task process switches the process state to busy when calling the Ontask callback function,
 The new task is no longer accepted, and when the Ontask function returns, it switches the process state to idle and then continues to receive the new task. * @param: $ws swoole_websocket_server Object * @param: $tid Task ProCess ID * @param: The $wid from ID indicates which worker process is coming from. $task _id and $wid are all globally unique, and different worker processes may have the same * @param: $data tasks to be performed * Note: The Ontask function executes with a fatal error exiting, or is forced by an external process to kill, The current task is discarded, but it does not affect other queued tasks/$ws->on (' Task ', function ($ws, $tid, $wid, $data) {switch ($data [' cmd ']) {case ' pus Htoclient ': $ret = Pushtoclienttask ($ws, $data [' key '], $data [' Val ']);
	Break //1.7.2 the above version, return the string in the Ontask function, indicating that the content is returned to the worker process. The OnFinish function is triggered in the worker process, indicating that the posted task is complete.
	The return variable can be any non-null PHP variable return $returnContent;
1.7.2 Previous versions, you need to call the Swoole_server->finish () function to return the results to the worker process//$ws->finish ($data);

});
 /** * The task process sends the results of the task processing to the worker process through the $ws->finish () method when the tasks posted by the worker process are completed in Task_worker. * @param: $ws swoole_websocket_server Object * @param: $tid task_id * @param: Results after $data task * Note: No Ontask events in the task process There is a call to the finish method or return result, the worker process does not trigger onfinish * The worker process that executes the onfinish logic is the same process as the worker process that issued the task tasks/$ws->on (' Finish '

, function ($ws, $tid, $data) {}); /** * After the TCP client connection is closed, this is recalled in the worker processfunction * In a function you can do something similar to deleting data stored in a business that interacts with each client * @param: $ws swoole_websocket_server Object * @param: $FD closed FD Interger * Param: $rid (optional), from which reactor thread * Note point: * 1. The OnClose callback function can cause a connection leak if a fatal error occurs. The netstat command will see a large number of close_wait states of TCP connections * 2. View Commands Netstat-anopc | grep port number to see whether the TCP receive and send queues are stacked and the TCP connection status is * 3. This event is triggered whether the client initiates close or the server-side active call $serv->close () closes the connection. Therefore, as long as the connection is closed, this function must be recalled * 4. After the 1.7.7+ version OnClose can still invoke the Connection_info method to get the connection information, and then close the TCP connection * 5 after the OnClose callback function has finished executing. This callback onclose indicates that the client connection is closed, so no $server->close ($FD) is required. Executing $serv->close ($FD) in your code throws a PHP error alert.
 That is, in the OnClose can no longer $ws->close (). * 6. The swoole-1.9.7 version modifies the $reactorid parameter, and when the server actively shuts down the connection, the underlying setting sets this parameter to-1, which can be judged by whether the $reactorid < 0来 resolution shutdown is initiated by the server or the client (which can be used when debug) * * *
	Ws->on (' Close ', function ($ws, $fd) {$redis = new Redis ();
	$redis->connect (Redis_host, Redis_port);
	$redis->auth (REDIS_PWD);
	$SARR = $redis->smembers (redis_fd_s. $fd); if (!empty ($SARR)) {foreach ((array) $sArr as $key => $sc) {$res = $redis->srem (redis_s_fd. $SC, $FD);
			$num = $redis->scard (redis_s_fd. $SC);
				if ($num = = ' 0 ') {$redis->srem (Redis_s_key, $SC);
			$redis->hdel (Redis_zs_key, $SC);
	}} $redis->del (redis_fd_s. $fd);
	$redis->close ();
echo "FD $fd has closed.\n";

});


/** * Open Swoole_websocket_server Service/$ws->start (); 
/** * After receiving the message to respond to the execution of the asynchronous task * @param: $ws swoole_websocket_sever Object * @param: $frame swoole_websocket_frame obejct * *
	function Handleclientdata ($WS, $frame) {$data = $frame->data;
	$redis = new Redis ();
	$redis->connect (Redis_host, Redis_port);
	$redis->auth (REDIS_PWD);
	$isMembers = $redis->sismember (redis_s_fd. $SC, $frame-&GT;FD);
	if (! $isMembers) {$res = $redis->sadd (redis_s_fd. $SC, $frame-&GT;FD);
	$redis->sadd (redis_fd_s $frame->fd, $SC);
	$isMembers = $redis->sismember (Redis_s_key, $SC);
	if (! $isMembers) {$redis->sadd (Redis_s_key, $SC); /** * Redis The callback function after subscription * @param: $ins Instance Instance * @param: $pattern match mode * @param: $channel Channel name * @param: $data data * Note points: Subscribe and psubscribe Two different ways of subscribing to the callback function is not the same number of parameters, the latter more than the $pattern parameter/function Sendtask ($ins, $pattern, $channel, $data)
	{//Meet some conditions, post to task process push $taskData = array (' cmd ' => ' pushtoclient ', ' key ' => $sc, ' Val ' => $data,);
Note that the taskwait is blocked synchronously, so the script is not fully asynchronous and non-blocking $GLOBALS [' ws ']->taskwait ($taskData); /** * Push Message to specified client * @param: $ws swoole_websocket_server Object * @param: $SC Stock code * @param: $data The data to be pushed * * * functi
    On Pushtoclienttask ($ws, $SC, $data) {$redis = new Redis ();
    $redis->connect (Redis_host, Redis_port);
	$redis->auth (REDIS_PWD);
	$fdList = $redis->smembers (redis_s_fd. $SARR [4]);
			if (!empty ($fdList)) {foreach ((array) $fdList as $FD) {$res = $GLOBALS [' ws ']->push ($FD, $data);
			echo "FD: $FD push $res. \ n";
				if (! $res) {//push failed, that is, the client has disconnected//removed the FD from all shares subscribed to the FD $sArrOfFd = $redis->smembers (redis_fd_s. $fd); if (!empty ($sArrOfFd)) {foreach ((array) $sArrOfFd as $key => $SC) {$res = $redis->srem (redis_s_fd. $SC, $FD);
						$num = $redis->scard (redis_s_fd. $SC);
							if ($num = = ' 0 ') {$redis->srem (Redis_s_key, $SC);
						$redis->hdel (Redis_zs_key, $SC);
			}} $redis->del (redis_fd_s. $fd);
{}}} $redis->close (); }


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.