Messages not getting sent via ZMQ - php

Currently, i am trying a simple code of sending/receiving messages using ZMQ. The code is as below
/* Create new queue object, there needs to be a server at the other end */
$queue = new ZMQSocket(new ZMQContext(), ZMQ::SOCKET_REQ);
$queue->connect("tcp://127.0.0.1:5555");
/* Assign socket 1 to the queue, send and receive */
$retries = 5;
$sending = true;
/* Start a loop */
do {
try {
/* Try to send / receive */
if ($sending) {
echo "Sending message\n";
$queue->send("This is a message", ZMQ::MODE_NOBLOCK);
$sending = false;
} else {
echo "Got response: " . $queue->recv(ZMQ::MODE_NOBLOCK) . "\n";
echo 'Complete';
break;
}
} catch (ZMQSocketException $e) {
/* EAGAIN means that the operation would have blocked, retry */
if ($e->getCode() === ZMQ::ERR_EAGAIN) {
echo " - Got EAGAIN, retrying ($retries)\n";
} else {
die(" - Error: " . $e->getMessage());
}
}
/* Sleep a bit between operations */
usleep(5);
} while (--$retries);
When i run this script in console, my output is
Sending message
Got response:
Complete
I believe that though there are no errors thrown, but still my message is not actually sent. I also ran netstat command but i didn't found any process listening on port 5555. Ideally there should be one(current). But no exception is thrown while making connection.
Is there something which i am missing?

When you say no process is listening on port 5555, it probably means that your server is not up and running. Your client will not throw any errors even if there is no server, it just sets up and waits for the server to come online (with your particular setup here, at least).
In this case, since you're using non-blocking mode, it'll send your message on the first pass through the loop (why are you sending the message in the loop at all?), but it won't actually send anything because the server isn't there. Then it'll attempt to receive on the second pass through the loop, but since the socket isn't ready to receive it looks like it'll just fail silently, without throwing an exception. Since no exception is thrown, it gets to your break statement, quits the loop, and you're done.
First things first, your send call should happen before the loop, it's something you want to do only once.
Then, when you recv, store the result in a variable and test for emptiness. Leave the try/catch code. The result should be something like this:
/* Create new queue object, there needs to be a server at the other end */
$queue = new ZMQSocket(new ZMQContext(), ZMQ::SOCKET_REQ);
$queue->connect("tcp://127.0.0.1:5555");
/* Assign socket 1 to the queue, send and receive */
$retries = 5;
echo "Sending message\n";
$queue->send("This is a message", ZMQ::MODE_NOBLOCK);
/* Start a loop */
do {
try {
/* Try to receive */
$response = $queue->recv(ZMQ::MODE_NOBLOCK);
if (!empty($response)) {
echo "Got response: " . $response . "\n";
echo 'Complete';
break;
}
else {
echo "we probably haven't even sent the original request yet, retrying ($retries)\n";
}
}
catch (ZMQSocketException $e) {
/* EAGAIN means that the operation would have blocked, retry */
if ($e->getCode() === ZMQ::ERR_EAGAIN) {
echo " - Got EAGAIN, retrying ($retries)\n";
} else {
die(" - Error: " . $e->getMessage());
}
}
/* Sleep a bit between operations */
usleep(5);
} while (--$retries);
echo "END OF LINE";
... keep in mind this is a minor fix to the client code that makes it behave a little more rationally, I still believe your actual problem is that the server isn't running.

Please add the server code. You are showing the client code. Since the problem seems to be in the server, and you also state that the server is not visible with netstat, the problem is most probably there.

Related

Error disconnecting Asterisk Manager

I am using Asterisk Manager to get events on incoming calls. I want to disconnect the Manager when a "Ring" event is received.
Below is my code which checks the "Ring" event upon receiving a call. My code disconnects the Manager, but also generates an error. Sometimes the error message appears multiple times.
What am I doing wrong?
<?php
require_once('phpagi/phpagi.php');
function newstatus($ecode,$data,$server,$port){
if (!isset($data['ChannelStateDesc'])){
$data['ChannelStateDesc'] = '';
}
print_r($data);
if ($data['Event'] == "Newchannel" && $data['ChannelStateDesc'] == "Ring") {
echo "Call Ringing!!!\n";
global $asm;
$asm->disconnect();
}
}
$e = 'ENTERQUEUE';
if ($e == 'ENTERQUEUE'){
$asm = new AGI_AsteriskManager();
$asm->connect();
$asm->add_event_handler("Newchannel", "newstatus");
$asm->wait_response(true);
}
Error Message:
PHP Warning: fgets(): 9 is not a valid stream resource in /scripts/phpagi/phpagi-asmanager.php on line 158
With $asm->connect(); you open a socket,
with $asm->disconnect(); you close the socket.
The Problem is, disconnect closes the socket in the eventcallback, but wait_response is a eventloop and the eventhandler get called again on a disconnected state.
If a request was just sent, wait_response will return the response. Otherwise, it will loop forever, handling events.
If you have remaining code, you could call that code (function) in the event handler (ie, new_status). If you want to do something on every event, you could register a wildcard event handler.
function newstatus($ecode, $data, $server, $port)
{
// ...
echo "Call Ringing!!!\n";
do_something($data);
// ...no disconnect necessary
}
function on_all_events(...)
{
// ...
}
function do_something($data)
{
var_dump($data);
}
add_event_handler('*', 'on_all_events');

Retry a try/catch when it fails

I've tried a few different try/catch loops to try and solve problems automatically but they always seem to cause the software to die.
$doLoop = true;
while ($doLoop) {
try {
//do a thing
insertIntoDb($data);
} catch (Exception $e) {
//try again
insertIntoDb($data);
//write error to file
writeError($e);
}
}
Here's my original try/catch.
The issue is sometimes the MySQL server 'goes away' and I need to catch that exception and keep retrying until it comes back.
What can I change here to get this to keep retrying until successful?
use a break as last statement in your try block to leave the loop only on success:
while (true) {
try {
// do something
insertIntoDb($data);
break;
}
catch (Exception $e) {
writeError($e);
}
// sleep 200ms to give the MySQL server time to come back up
usleep(200000);
}
But you should also limit the number of retries by using a for loop instead.
Otherwise, your code might run in an infinite loop:
// limit the number of retries
for ($i=1; $i <= 3; $i++) {
try {
// do something
insertIntoDb($data);
break;
}
catch (Exception $e) {
writeError($e);
}
// sleep 200ms to give the MySQL server time to come back up
usleep(200000);
}
Also note the usleep() call:
This is important because otherwise the PHP process would take all resources (100% CPU) while retrying as fast as possible. You can adjust the value to fit your needs. (maybe 200ms is too long or too short in your case)
Also note that you may need to reconnect to the MySQL DB on failure! I did not include code for that case in my example.
This will only work, if your function insertIntoDb will throw an Exception. If you use mysql* functions, then it won't work.
After insertIntoDb($data); you should set $doLoop = false

Bitcoin sendfrom not returning any errors

I am trying to validate bitcoin engine respond once executing with correct amount within the account balance and correct wallet I am getting transaction ID, but if I enter amount too much and fake wallet I am not receiving any error in return just a blank page with html, head and body elements. Is there is any debug mode or what I can do to receive any response?
$message = ($bitcoin->sendfrom($mywallet,$to_wallet,$wammount));
I am using jsonRPCClient to connect with bitcoin engine.
however when I do that in console using RPC commands
I am getting this : Account has insufficient funds (code -6)
code for redirection
if ($message !== '') {
ob_start();
header("Location: mywallet.php?error=done");
die();
} else {
ob_start();
header("Location: mywallet.php?error=true");
die();
}
Update Yes correct I will more ob_start(); above, thing is that once trying (try,catch) event I am getting blank page upon SUCCESS (so not transaction ID like with normal way I am doing I am getting back transaction ID) upon FAIL I am getting Unable to connect to Bitcoin Server. What I just need sounds very simple, how do I verified that transaction is SUCCESSFUL or FAIL, SUCCESSFUL -> I got ID in return, FAIL -> I have got Error in return. SO I can divert users to right places on the page after form is submitted. Actualy I am doing is withdraw funds form, where user inserts amount and his wallet to get funds back from bitcoin account to his private account. Hope this will helps to understand.
UPDATE 2 I have changed construction for that and seems to is working very well, basically is looking for "Unable" word as transaction ID doesn't have that word and other exception I am getting is "Unable to connect to server..." Thank you for guiding me. Any feedback ?
try {
$message = ($bitcoin->sendfrom($mywallet,$to_wallet,$wammount));
}
catch (Exception $e) {
$e->getMessage();
}
// exit;
if (!strpos($e,'Unable') !== false){
header("Location: mywallet.php?error=done");
die();
} else {
header("Location: mywallet.php?error=true");
die();
}
What bitcoin php library are you using? Looks like maybe this one?
If that's the case, it doesn't return an error message, it throws BitCoinClientException
So you need something like
try {
$message = ($bitcoin->sendfrom($mywallet,$to_wallet,$wammount));
}
catch (Exception $e) {
echo $e->getMessage();
}
Updating
The ob_start seems superfluous because you don't output anything before the header location. Unless you have output something before you've reached this point in which case you can't send a header. So you'd need to move the ob_start up towards the top of the script before any output.
Also you aren't sending message to the wallet.php script. Or are you done with it at that point?
RE: update 2
One thing I might add is the possibility of some other exception message occuring we haven't thought of yet that doesn't contain the "Unable." I'd do something more like:
$errorOccured = false;
try {
$message = ($bitcoin->sendfrom($mywallet,$to_wallet,$wammount));
}
catch (Exception $e) {
$errrorMessage = $e->getMessage();
$errorOccured = true;
}
if (!$errorOccured) {
...
}
else {
header("Location: mywallet.php?error=true&errormsg=" . $errorMessage);
...
}
This would require modifying mywallet.php to accept $errorMessage as an additional GET parameter so you can send it back to the user. Might be nice to additionally use another parameter for sending $message on success which would contain the transaction ID.

Socket php server not showing messages sent from android client

Hi I am a newbie in these kind of stuff but here's what i want to do.
I am trying to implement a chat application in which users will send their queries from the website and as soon as the messages are sent by the website users.It will appear in the android mobile application of the site owner who will answer their queries .In short I wanna implement a live chat.
Now right now I am just simply trying to send messages from android app to php server.
But when I run my php script from dreamweaver in chrome the browser keeps on loading and doesn't shows any output when I send message from the client.
Sometimes it happened that the php script showed some outputs which I have sent from the android(client).But i don't know when it works and when it does not.
So I want to show those messages in the php script as soon as I send those messages from client and vice versa(did not implemented the vice versa for client but help will be appreciated).
Here's what I've done till now.
php script:
<?php
set_time_limit (0);
$address = '127.0.0.1';
$port = 1234;
$sock = socket_create(AF_INET, SOCK_STREAM, 0);
socket_bind($sock, $address, $port) or die('Could not bind to address');
socket_listen($sock);
$client = socket_accept($sock);
$welcome = "Roll up, roll up, to the greatest show on earth!\n? ";
socket_write($client, $welcome,strlen($welcome)) or die("Could not send connect string\n");
do{
$input=socket_read($client,1024,1) or die("Could not read input\n");
echo "User Says: \n\t\t\t".$input;
if (trim($input) != "")
{
echo "Received input: $input\n";
if(trim($input)=="END")
{
socket_close($spawn);
break;
}
}
else{
$output = strrev($input) . "\n";
socket_write($spawn, $output . "? ", strlen (($output)+2)) or die("Could not write output\n");
echo "Sent output: " . trim($output) . "\n";
}
}
while(true);
socket_close($sock);
echo "Socket Terminated";
?>
Android Code:
public class ServerClientActivity extends Activity {
private Button bt;
private TextView tv;
private Socket socket;
private String serverIpAddress = "127.0.0.1";
private static final int REDIRECTED_SERVERPORT = 1234;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
bt = (Button) findViewById(R.id.myButton);
tv = (TextView) findViewById(R.id.myTextView);
try
{
InetAddress serverAddr = InetAddress.getByName(serverIpAddress);
socket = new Socket(serverAddr, REDIRECTED_SERVERPORT);
}
catch (UnknownHostException e1)
{
e1.printStackTrace();
}
catch (IOException e1)
{
e1.printStackTrace();
}
bt.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
try
{
EditText et = (EditText) findViewById(R.id.EditText01);
String str = et.getText().toString();
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);
out.println(str);
Log.d("Client", "Client sent message");
}
catch (UnknownHostException e)
{
tv.setText(e.getMessage());
e.printStackTrace();
}
catch (IOException e)
{
tv.setText(e.getMessage());
e.printStackTrace();
}
catch (Exception e)
{
tv.setText(e.getMessage());
e.printStackTrace();
}
}
});
}
}
I've just pasted the onclick button event code for Android.Edit text is the textbox where I am going to enter my text.
The ip address and port are same as in php script.
I'd recommend using an event driven framework for handling your connections.
There's a fairly decent example called React but it has tons of other stuff in there you'll probably want to strip out so your app doesn't depend on hundreds of external components.
React uses a message loop based on libevent if you have it installed, or stream_select otherwise.
You handle events with closures, something like:
$client->on('read', function($data) use ($client) {
$client->onRead($data);
});
With this you will be able to handle lots of simultaneous connections, and it will not tie up all of your CPU.
Your code will be executed when something happens.
If nothing else, have a look at how it works, you'll get a better understanding of how to create a non-blocking event driven socket server.
First of all - your server will handle only one client connection at a time, which doesn't makes sense for chat.
I can't see how you deal with socket connection on Android side but anyway it will not allow you to connect again as long as your script execution will not execute "socket_accept()" and wait for connection.
You should run 1 loop process to grab new client connections and fork into separate process each connected client.
Take look at my same lightweight PHP server I wrote here which is based on the same principle:
https://github.com/webdevbyjoss/Aaaaa---space-ships-combat-multiplayer-game/blob/master/server/server.php
Ignore the Websockets related "doHandshake()" and "WebSocketFrame::decode/WebSocketFrame::encode" but you should be OK with the rest.
Generally it runs the loop
while (true)
if (($msgsock = socket_accept ( $sock )) === false) {
echo "socket_accept() failed: reason: " . socket_strerror ( socket_last_error ( $sock ) ) . "\n";
break;
}
// We got a client connected, lets process it in separate thread
if (($pid = pcntl_fork()) === -1) {
echo "pcntl_fork() failed. Make sure you are on Linux sustem, but not on Windows\n";
break;
}
if (!$pid) { // client
handleClient($msgsock);
exit();
}
// parent server will wait to accept more clients connections in new loop
}
And inside handleClient() function you should have a separate loop to communicate with the client.
while (true) {
if (false === ($buf = socket_read ( $msgsock, 2048, PHP_BINARY_READ ))) {
echo "socket_read() failed: reason: " . socket_strerror ( socket_last_error ( $msgsock ) ) . "\n";
return;
}
if (empty($buf)) { // do disconnection check
echo "Client disconnected\n";
return;
}
// -------------------------------------------------------------
// PUT YOUR BUSINESS LOGIC HERE
// TO HANDLE MESSAGES OF THE CHAT AND GENERATE RESPONSE TO USER
// I RECOMMEND TO USE SOMETHING LIKE MEMCACHE/REDIS/MONGO/MYSQL/TXT-FILES
// FOR MULTIPROCESS DATA INTERCHANGE
// -------------------------------------------------------------
// transfer data to client
socket_write($msgsock, $returnText, strlen($returnFrame));
}
socket_close ( $msgsock );
Have you tried adding '\r\n' into value of EditText before sending to server yet? I think the problem isn't connection between client and server because it doesn't show error when connection fail. Maybe in your case socket_read($client,1024,1) must stop reading at a '\r\n'.
Update: Your local ip maybe cause connection error. Have a look at this link
Your address 127.0.0.1 will resolve to the machine the code is running on. So the app actually tries to connect to itself. type ipconfig /all on the MSDOS console and use that address instead.

php get message from rabbitmq error

My amqp extension version is 1.0.1 & AMQP protocol version is 0-9-1
get messages from queue :
<?php
try {
$conn = new AMQPConnection() ;
$conn->setLogin('guest') ;
$conn->setPassword('guest') ;
$conn->connect() ;
if ($conn->isConnected()) {
$channel = new AMQPChannel($conn) ;
if ($channel->isConnected())
{
$queue = new AMQPQueue($channel) ;
$queue->setName('test_queue') ;
$queue->setFlags(AMQP_DURABLE | AMQP_AUTODELETE) ;
$queue->declare() ;
$messages = $queue->get(AMQP_AUTOACK) ;
print_r($messages->getBody()) ;
}
} else {
echo "connect failure ... " ;
}
$conn->disconnect() ;} catch (Exception $e) {
echo $e->getMessage() ;}?>
and it doesn't work ..
Server channel error: 406, message: PRECONDITION_FAILED - parameters for queue 'test_queue' in vhost '/' not equivalent
It seems to me that the queue already exists and it was declared (created) previously with different parameters in the vhost. Queues need to be declared exactly with the same parameters every time (or deleted and recreated with the desired parameters). Try deleting the queue via the management plugin (http://www.rabbitmq.com/management.html) and then running your script again
If your queue has already been created you don't need to create it (using 'declare' method) and bind with exchange once again. IMHO you shouldn't do it as a) these actions require administrative privileges b) it's enough to to it only once c) you might not have got administrative rights on production and your code would be broken.
I believe it's better to create and bind all required queues with management console or any other tool you like and then receive messages this way
// consider using connection more than once. that's only for illustration purposes.
$connection = new AMQPConnection([ put your credentials here ]);
$connection->connect();
if(!$connection->isConnected()) {
throw new Exception('Connection failed.');
}
$chnlObj = new AMQPChannel($connection);
$queObj = new AMQPQueue($chnlObj);
$queObj->setName('yourQueueName');
echo $queObj->get(AMQP_AUTOACK)->getBody();
// consider using connection more than once. that's only for illustration purposes.
$connection->disconnect();

Categories