I've currently got a web socket server running and working with Ratchet PHP. I'm not at the stage where I want external scripts to communicate with my server. I can successfully push data to it using ZMQ:
push.php
$json = ['name' => 'Joe Bloggs'];
$context = new ZMQContext();
$socket = $context->getSocket(ZMQ::SOCKET_PUSH, 'Push Notification');
$socket->connect("tcp://localhost:5555");
$socket->send(json_encode($json));
Then in my webserver script I can send this to a method (onNewPush) to do something with it when the push.php file is run (ran?):
...
$push = $context->getSocket(ZMQ::SOCKET_PULL);
$push->bind('tcp://127.0.0.1:5555');
$push->on('Push Notification', array($pusher, 'onNewPush'));
...
So this works fine, but I'm having trouble trying to receive a response back. I'm trying something like:
pull.php
$context = new ZMQContext();
$socket = $context->getSocket(ZMQ::SOCKET_REQ, 'Pull Notification');
$socket->connect("tcp://localhost:5554");
$socket->send('data');
echo $socket->recv();
Then in my server script:
$pull = $context->getSocket(ZMQ::SOCKET_PULL);
$pull->bind('tcp://127.0.0.1:5554');
$pull->on('message', array($pusher, 'onPull'));
My $pusher variable loads my file which implements a few Ratchet Interfaces. But essentially I'm just returning a string:
public function onPull()
{
return "some data";
}
When running pull.php I get the error:
Fatal error: Uncaught exception 'ZMQSocketException' with message 'Failed to receive message: Not supported' in websockets\pull.php:9 Stack trace: #0 websockets\pull.php(9): ZMQSocket->recv() #1 {main} thrown in websockets\pull.php on line 9
Does anyone know why?
Also what importance does the second parameter on getSocket() have? Just seems like a string which is never used again.
Cheers
UPDATED
In your pull.php file, you've got a REQ socket connecting to a PULL socket. Check out the docs to see compatible socket pairs. In particular, it appears that you want a REQ-REP pair so that your client can request data and your server replies with a response. You'd use PUSH-PULL if your server queues up data ready for the next client, and then your client pulls whatever is next from the queue.
In either event, you cannot connect a REQ socket to a PULL socket or a PUSH socket.
I don't fully understand your use case or communication architecture from the listed code or naming scheme, so I don't know how much more detail I can give than that, feel free to clarify what's going on and I might be able to advise more definitively what socket strategy you should be using.
You have this line in your pull.php:
echo $socket->recv();
Push socket is for sending messages, not receiving them. That's probably where the exception comes from.
Also: The first parameter of method on() on pull sockets should be 'message'.
$pull->on('message', array($pusher, 'onPull'));
Related
I have a server running and waiting/listening for connections. The server is based on Mark Framework which is using Workerman. So far I'm able to start the server and when I load the URL/host on the browser it shows content (in this case I'm expecting a simple Hello world).
This is index.php which I use to start the server
use Mark\App;
require 'vendor/autoload.php';
$api = new App('http://127.0.0.1:8080');
$api->count = 2; // process count
$api->any('/', function ($requst) {
return 'Hello world';
});
$api->start();
Now, I have a simple Laravel app that I want when I open a certain page to connect to that server and show the content from it.
I'm not sure how to do this. What I have so far in the controller is this
public function index() {
try {
$host = "127.0.0.1";
$port = 8080;
$resource = stream_socket_client("tcp://$host:$port", $error_no, $error_str, 20, STREAM_CLIENT_CONNECT);
$lines = stream_get_line($resource, 8192);
var_dump($lines);
} catch(Exception $e){
return response($e->getMessage(), 500);
}
var_dump($resource);
return View::make('index');
}
var_dump($resource) which is a variable for the connection shows
resource(10) of type (stream)
var_dump($lines); shows false which I guess is because the $resource doesn't make any connection
bool(false)
Any ideas here on how to approach this?
TCP connection does not rely on any protocol, it's just a pure data transfer protocol which enables you to transfer bytes with ACL confirmation. You name it TCP and you include some Mark Framework which is http protocol based process.
The docs say it helps you to quickly write APIs with php. It means it's not a TCP raw server with custom protocol but it is a http protocol oriented server which is simply a REST API ready for http GET/POST requests to make your life easier.
You can do the same things with laravel on both sides until you need realtime connection. Realtime socket connections are made via javascript because HTTP is not built for this.
From laravel side just read: https://laravel.com/docs/9.x/http-client#making-requests
I might overwatched something, but sockets are rarely used in web. By calling TCP you called for 'sockets' and your post seems to negate your need for them.
I want to subscribe the Spring framework WebSocket and receive the reply.
According to my target WebSocket server, the communication is done using STOMP publish protocol (Build based on Java Springframework API) https://stomp.github.io/stomp-specification-1.1.html
Now the client that I am working on, is build based on PHP and using https://github.com/Textalk/websocket-php/ for websocket client.
My idea to receive the server response is to follow the STOMP over Websocket technique based on this guy's answer Websocket Client not receiving any messages.
Using the current websocket client, I perform these steps
Send Connection (request?)
Send Subscription
Actively receive the reply
$client = new WebSocket\Client($ws_url);
//Step 1 Inintate connection;
$open_msg = "CONNECT\naccept-version:1.0,1.1,2.0\n\n\x00\n";
//Step 2 Subscribe Request;
$client->send($open_msg);
$subs = "SUBSCRIBE\nid:0\ndestination:/user/queue\nack:auto\n\n\x00\n";
$client->send($subs);
while (true) {
try {
$message = $client->receive();
echo $message;
// Act[enter image description here][4] on received message
// Later, Break while loop to stop listening
} catch (\WebSocket\ConnectionException $e) {
// Possibly log errors
}
}
$client->close();
The connection (Step 1) is done and tested.
current send and receive result image
Since it is running on the loop, the Received is always printed.
Does anyone know why the API did not send reply?
It turns out, I have to implement the other Websocket library instead
Instead of using https://github.com/Textalk/websocket-php/ , I moved on and use https://github.com/ratchetphp/Pawl
I don't know what just happened. But I think Textalk is synchronous websocket library and ratchet is asynchronous websocket library.
My current hypothesis is whenever you want to do Stomp over websocket, make sure
Send Connection message ("CONNECT\naccept-version:1.0,1.1,2.0\n\n\x00\n")
Send subscription ("SUBSCRIBE\nid:0\ndestination:/user/queue\nack:auto\n\n\x00\n")
Use the asynchronous Websocket instead of synchronous one
Have a nice day
Goal
I am developing a JSON endpoint that basically reads data from a server-side COM port into a file (on the server end) when a user sends a GET request to it. The response from the server has to be a properly formed JSON response containing the name of the file where the contents were dumped to. If the COM port takes too long to respond, the file is closed and still considered valid with whatever contents it did read from the COM port. A valid response is still provided.
Problem
When the COM port is no longer being fed data, it blocks until the script times out. This results in an error and IIS provides a generic error page on a json endpoint. This is not valid json, but it also does not contain the name of the file where the com data was dumped to.
Details
I have to use the PHP Direct IO extension to interface with a serial com port.
This is blocking IO, and on windows, asynchronous IO is not supported (as far as I have seen.)
register_shutdown_function does not guarantee it is executed while a connection is still open to the client, so I cannot use this to print a valid response.
For your JSON endpoint, you could create a wrapper script that calls your IO script. Set a timeout for your attempt to get a response from it, and then return JSON with either whatever it got from the script, or some custom message if the script timed out.
$timeout = 5; // some reasonable time less than the wrapper script timeout
$data = ['filename' => 'something']; // create the file name
$q = http_build_query($data); // pass it to the IO script
$context = stream_context_create(['http'=> ['timeout' => $timeout]]);
$response = file_get_contents("http://yourserver/io_script.php?$q", false, $context);
echo json_encode($data + ['data' => $response ?: 'no data']);
Hello I'm quite new to using sockets and am not that familiar with them yet, Basically all i am trying to do is pass a string variable to a web address (e.g. www.example.com/index.php?Example=StringExample) and then get a response, so for example it would return "Test Example" if index.php looked like this:
<?php
if($_GET['Example'] == "StringExample")
{
echo "Test Example";
}
?>
Here is what I've tried in c++:
struct sockaddr_in SocketAddress;
hostent* addr = gethostbyname("www.example.com/index.php?Example=StringExample");
int sizeofaddr = sizeof(addr);
SocketAddress.sin_addr.s_addr = inet_addr(addr->h_name);
SocketAddress.sin_port = htons(80);
SocketAddress.sin_family = AF_INET;
SOCKET Connection = socket(AF_INET, SOCK_STREAM, NULL);
if (connect(Connection, (SOCKADDR*)&addr, sizeofaddr) != 0)
{
return 0; //Failed to Connect
}
char buffff[256];
recv(Connection, buffff, sizeof(buffff), NULL);
//"Test Example" now stored in buffff
What am i doing wrong?
Btw in my case i would not like to use any libraries like boost or anything like that. Thanks for the help :)
gethostbyname("www.example.com/index.php?Example=StringExample");
"www.example.com/index.php?Example=StringExample" is not a valid server name. This is an entire URL; a server name would be "www.example.com". gethostbyname() takes the name of a server, and not a URL, and returns its IP address. Additionally, gethostbyname() has been obsoleted. New code should use the getaddrinfo(3) function, instead.
This is obviously an HTTP URL. To download a document via HTTP it is a lot more work than just connecting a socket. Establishing a socket connection is just the first step in the process of downloading a document from an HTTP server. This must be followed by sending a valid HTTP request, and then receiving an HTTP response from the server.
There are many libraries, such as curl, that implement the entire client-side process needed to download an HTTP document, that will handle the socket connection themselves.
But there's nothing wrong with trying to implement this yourself, either. It's a good programming excersize.
So, after resolving www.example.com's IP address, you will need to
1) Connect to the server's port 80, the default HTTP port.
2) Send an HTTP request for "/index.php?Example=StringExample".
3) Parse the HTTP response.
The specification for HTTP requests and responses is defined by RFC 2616, which you can consult for complete documentation of how HTTP requests and responses are structured.
If you want to access a web server with sockets, you have to keep in mind:
You can open a tcp/ip connection to your web server
BUT afterwards you have to do the http protocol by yourself
In case of your example:
hostent* addr = gethostbyname("www.example.com");
//...
const char* request = "GET index.html"
send(Connection, request, strlen(request), NULL)
//fetch index.html with a recv and parse it
To be more precise, if you want to access your server, you have to take a look how GET, PUT, POST, etc. are implemented in the http protocol, send the proper commands to your web server and recv() the replies
I’m trying to invoke a WCF service (.NET) from PHP. It’s a little more complicated than just using a SoapClient since the service uses a WS2007FederationHttpBinding to authenticate.
Here’s the code I’m using at the moment. I haven’t even added credentials as I’m not sure how, but regardless, I’m not even at the point where I’m getting access denied errors.
$wsdl = "https://slc.centershift.com/sandbox40/StoreService.svc?wsdl";
$client = new SoapClient($wsdl,array(
//'soap_version'=>SOAP_1_2 // default 1.1, but this gives 'Uncaught SoapFault exception: [HTTP] Error Fetching http headers'
));
$params = array();
$params['SiteID'] = 123;
$params['GetPromoData'] = false;
$ret = $client->GetSiteUnitData(array('GetSiteUnitData_Request'=>$params));
print_r($ret);
Which WSDL should I be pointing to?
https://slc.centershift.com/Sandbox40/StoreService.svc?wsdl
Seems to be very short, but includes a reference to (note the wsdl0) https://slc.centershift.com/Sandbox40/StoreService.svc?wsdl=wsdl0
https://slc.centershift.com/Sandbox40/StoreService.svc?singleWsdl
Seems to have everything in it.
Do I need to specify SOAP 1.2? When I do, I get a connection timeout ([HTTP] Error Fetching http headers). When I don’t, the default of SOAP 1.1 is used and I get a [HTTP] Cannot process the message because the content type 'text/xml; charset=utf-8' was not the expected type 'application/soap+xml; charset=utf-8'. Is this because I’m not authenticated yet, or because I’m using the wrong SOAP version?
How to authenticate in PHP? Here’s the corresponding .NET/C# code. Do I need to somehow put these as SOAP headers? Or am I thinking about it all wrong, and I need to do some kind of authentication before I even call the method (from what I read, I’m supposed to get a token back and then use it for all future method calls – I think I see an example of this in an answer here on Stack Overflow.
If I call $client->__getFunctions(), using either WSDL and either SOAP version, I’m getting a valid list of all functions, so I assume either of these is fine and my real issue is the authentication.
Other programmers I’ve talked to had spent time trying to get this to work, but gave up and instead implemented a proxy in .NET. They pass their parameters from PHP to their own unsecured .NET service, which in turn calls this secure service. It works, but seems crazily inefficient to me, and counter-productive, as the purpose of WCF is to support all types of clients (even non-HTTP ones!).
I’ve read How to: Create a WSFederationHttpBinding on MSDN, but it didn’t help.
You can use this URL for WSDL https://slc.centershift.com/Sandbox40/StoreService.svc?singleWsdl. This WSDL has all definitions.
You have to use 1.2 because this webservice works with SOAP 1.2 version. I tried it with 1.1 and 1.2 and both of them gived error. 1.1 is version error, 1.2 is timeout error. I think there is an error at this test server. I used it with svcutil to generate code but it gived error too. Normaly it should get information and generate the code example to call service.
Normally you can add authenticate parameters with SoapHeader or directly add to options in SoapClient consruct (if service authentication is basic authentication). I write below code according to your screenshot. But it gives timeout after long wait.
$wsdl = "https://slc.centershift.com/sandbox40/StoreService.svc?wsdl";
$client = new SoapClient($wsdl,array('trace' => 1,'soap_version' => SOAP_1_2));
$security = array(
'UserName' => array(
'UserName'=>'TestUser',
'Password'=>'TestPassword',
'SupportInteractive'=>false
)
);
$header = new SoapHeader('ChannelFactory','Credentials',$security, false);
$client->__setSoapHeaders($header);
$params = array();
$params['SiteID'] = 100000000;
$params['Channel'] = 999;
try {
$ret = $client->GetSiteUnitData($params);
print_r($ret);
}catch(Exception $e){
echo $e->getMessage();
}
__getFunctions works, because it prints functions defined in WSDL. There is no problem with getting WSDL information at first call. But real problem is communication. PHP gets WSDL, generates required SOAP request then sends to server, but server is not responding correctly. SOAP server always gives a response even if parameters or request body are not correct.
You should communicate with service provider, I think they can give clear answer to your questions.
Having worked with consuming .NET WS from PHP before I believe you would need to create objects from classes in PHP that matches the names that .NET is expecting. The WSDL should tell you the types it is expecting. I hope this assist with your path forward!
If the SOAP call works from a C# application, you could use Wireshark (with the filter ip.dst == 204.246.130.80) to view the actual request being made and then construct a similar request from php.
Check this answer to see how you can do a custom SOAP call.
There's also the option of doing raw curl requests, since it might be easier to build your xml body, but then you would have to parse the response yourself with simplexml.