I'm trying to determine how to setup a web socket for the first time ever so a working minimal example with static variables (IP address for example instead of getservbyname) will help me understand what is flowing where.
I want to do this the right way so no frameworks or addons for both the client and the server. I want to use PHP's native web sockets as described here though without over-complicating things with in-depth classes...
http://www.php.net/manual/en/intro.sockets.php
I've already put together some basic JavaScript...
window.onload = function(e)
{
if ('WebSocket' in window)
{
var socket = new WebSocket('ws://'+path.split('http://')[1]+'mail/');
socket.onopen = function () {alert('Web Socket: connected.');}
socket.onmessage = function (event) {alert('Web Socket: '+event.data);}
}
}
It's the PHP part that I'm not really sure about. Presuming we have a blank PHP file...
If necessary how do I determine if my server's PHP install has this socket functionality already available?
Is the request essentially handled as a GET or POST request in
example?
Do I need to worry about the port numbers? e.g. if
($_SERVER['SERVER_PORT']=='8080')
How do I return a basic message on the initial connection?
How do I return a basic message say, five seconds later?
It's not that simple to create a simple example, I'm afraid.
First of all you need to check in php configuration if the server is configured for sockets with the setting enable-sockets
Then you need to implement (or find) a websocket server that at least follows the Hybi10 specification (https://datatracker.ietf.org/doc/html/draft-ietf-hybi-thewebsocketprotocol-10) of websockets. If you find the "magic number" 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 in the code for the header, you can be sure it does follow at least Hybi06 ...
Finally, you need to have access to an admin console on the server in order to execute the PHP websocket server using php -q server.php
EDIT: This is the one I've been using a year ago ... it might still work as expected with current browsers supporting Websockets: http://code.google.com/p/phpwebsocket/source/browse/trunk/+phpwebsocket/?r=5
Related
I have a Java Spring Application with a Tomcat server that listen on kafka topic. I want to display all messages in a real-time mode on the web page. Therefore, when a kafka messages is arrived in the backend I want to see it on my web page. I don't know a good approach to push kafka message directly to the front-end and display it on web page. Is someone could help my with a solution and some examples that could help? Thanks!
I have implemented a system like this in Java for my last employer, albeit not with Spring/Tomcat. It was consuming messages from Kafka and serving them on a web socket to be displayed in the browser. The approach I followed was to use akka-stream-kafka and akka-http for web-socket support. The benefit of that is both are based on akka-streams which makes it an easy fit for streaming data.
While you can embed akka-http in your spring app running inside tomcat, it may not feel the most natural choice any more as spring framework already has its own support for both kafka and websockets. However, if you're not familiar with either, then jumping on the akka approach may be easiest and the core logic goes along these lines (I can't share the code from work so have just put this together from the examples in the docs, not tested):
public Route createRoute(ActorSystem system) {
return path("ws", () -> {
ConsumerSettings<byte[], String> consumerSettings = ConsumerSettings.create(system, new ByteArrayDeserializer(), new StringDeserializer())
.withBootstrapServers("localhost:9092")
.withGroupId(UUID.randomUUID().toString()) //this is so that each client gets all messages. To be able to resume from where a client left off in case of disconnects, you can generate in on the client side and pass in the request
.withProperty(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest")
return handleWebSocketMessages(
Flow.fromSinkAndSourceCoupled(
Sink.ignore(),
Consumer.committableSource(consumerSettings, Subscriptions.topics("topic1"))
.map(msg -> TextMessage.create(msg.record().value()))
)
);
}
}
To expose this route you can follow the minimalistic example, the only difference being the route you define needs the ActorSystem:
final Http http = Http.get(system);
final ActorMaterializer materializer = ActorMaterializer.create(system);
final Flow<HttpRequest, HttpResponse, NotUsed> routeFlow = createRoute(system).flow(system, materializer);
final CompletionStage<ServerBinding> binding = http.bindAndHandle(routeFlow,
ConnectHttp.toHost("localhost", 8080), materializer);
Once you have your messages published to the websocket, the front end will code will of course depend on your UI framework of choice, the simplest code to consume ws messages from javascript is:
this.connection = new WebSocket('ws://url-to-your-ws-endpoint');
this.connection.onmessage = evt => {
// display the message
To easily display the message in the UI, you want the format to be something convenient, like JSON. If your Kafka messages are not JSON already, that's where the Deserializers in the first snippet come in, you can convert it to a convenient JSON string in the Deserializer or do it later on in the .map() called on the Source object.
Alternatively, if polling is an option you can also consider using the off-the-shelf Kafka Rest Proxy, then you only need to build the front-end.
Zup coders. I've implemented a simple website that uses Web Sockets PHP (Consik Yii2 solution: https://github.com/consik/yii2-websocket) vs JS (Html5).
Everything is working fine, I only have one issue with my solution, making sure the server is always alive.
I though about saving the WebSocket Instance into Cache and throw a cron that checks the state of the instance. I installed memcached and found out that i can´t save a serialized version of the WebSocket Server instance. ¿Is this a good solution? ¿Would Redis Caché fix this?
I also thought about using client side JS to react to "Error during WebSocket handshake: Unexpected response code: 200" but i can't seem to get it working. I also don't like making the URL that starts websockets public.
Ex:
connect = function(){
websocket = new WebSocket(webSocketURL);
websocket.onerror = function(){
$.get( "/startWebSocketServer",
function(data){
connect();
}
);
};
};
connect();
Thanks!
I think that as matter of fact you need a process supervisor who takes care to "supervise" your server process and do actions in response of process/system events like crash, restart etc..
There are several solutions for each case (standard OS implementations, personal preferences, fit your need), here a list http://without-systemd.org/wiki/index.php/Init , Service managers section could best fit your needs.
Supervisord is easy to setup and configure, it could be a good start thanks to a good bunch of examples around the net.
Solution 1: using a cache could not be the most orthodox way to implement a custom-made supervisor.
Solution 2: is legit as long as it informs user about a problem, the call to an exposed endpoint to start a service IMHO could be a security flaw.
I have the following js code:
stompClient.subscribe('/topic/clients', function (calResult) {
updateClientsTable(JSON.parse(calResult.body));
});
$.get("/clients", null);
and following server code(last line invokes it):
#GetMapping(value = {"/clients"})
#ResponseBody
public void loadClients() {
brokerMessagingTemplate.convertAndSend("/topic/clients", clientService.getClientList());
}
Sometime front-end misses result of $.get("/clients", null);
As I understand problem: at the moment of result getting on front end, subscriptions is not happens.
if to put $.get("/clients", null); below in the code - all works fine.
Can you explain how to await subscriptions established?
I think it would make more sense to not mix REST requests with this messaging pattern.
Have you considered sending the "updateClients" command through SockJS into an "/apps/updateClients" channel which replies to the "/topic/clients" channel?
As #light_303 already mentioned, mixing HTTP requests with notification mechanism isn't good. You can register moment, when client connects (GET request on /clients), but you can't register when he disconnects.
You should think in one of the next ways. When user subscribes to /topic/clients:
You individually send him response with all client list and then push updates only.
You individually send him current server time or some kind of ID and then push updates only. User uses given time/ID in GET request to /clients and receives full client list on that moment. This option can be good in situation, when you have incremental updates (i. e. adding new elements to list) and otherwise not so good.
Check this question: Sending message to specific user on Spring Websocket.
This is actually ridiculous, how Spring can complicate things. I recommend you to look on another frameworks for real-time web communication, such as Vert.x or Netty and on Go programming language. Use WebSockets or SockJS instead of STOMP. All that technologies can give you more flexible and performant solution in obvious way. Also, check Centrifugo project, maybe it's relevant to your task.
You can use #SubscribeMapping annotation from spring-messaging.
If you have spring-messaging configured as described here and here, the server-side code could look like following:
#Controller
public class MessagingController {
#SubscribeMapping("/clients")
public List<Client> loadClients() {
return clientService.getClientList();
}
}
This way you don't have to call $.get("/clients", null); because JS message handler receives result of loadClients() call right after subscription happens. JS code would look like:
stompClient.subscribe('/topic/clients', function (calResult) {
updateClientsTable(JSON.parse(calResult.body));
});
I have a school project where i need to create an instant webbased messageing system.
Ive looked into PHP sockets to complete this task PHP socket manual
From these im starting to see a pattern. As you well know PHP can only run once (from top to bottom) and from these examples i can see that a while loop is what makes the socket listen for new connections. (meaning the php script never stops) these examples the echo the output of the socket.
as far as i can see this is great if you just want a plain site.
However this is not the case. I want to build this application using JavaScript to "ask" the socket if there is any new messages and if there is then render the messages accordingly.
Since im very new to PHP sockets im not sure if this should be done purely by PHP or if it is possible to use JavaScript to listen to the socket (via Ajax) and then print the output as a JSON?
I recommend you to use a third party library (well, an recommend you again this library: cboden/ratchet). Read its tutorials and you will have a cleaner look at how to communicate between browsers ans servers using WebSocket protocol.
The server is absolutely able to be implemented with pure PHP!
In general for push based notifications the protocol you will want (which only works with newer browsers) is WebSockets.
There are a variety of libraries and services which can do this for you:
Pusher, is an online service which can integrate with a variety of languages to give you real time functionality. https://pusher.com/
In JavaScript only, and if you have node you should look at socket.io : http://socket.io/
In .NET land, there is SignalR which is fantastic http://signalr.net/
Not only is it possible to do with PHP but it's also trivial with Thruway. Thruway is a WAMPv2 PHP client/router that uses Ratchet for the Websocket transport. WAMP gives you Sub/Pub and RPC over WebSockets.
You would need to create a simple php router and start it from the command line. Something like this:
<?php
require 'vendor\autoload.php';
use Thruway\Peer\Router;
use Thruway\Transport\RatchetTransportProvider;
$router = new Router();
$transportProvider = new RatchetTransportProvider("127.0.0.1", 9090);
$router->addTransportProvider($transportProvider);
Then on the client, use AutobahnJS or if you're using angular, you can use angular-wamp.
If you still have questions, I'll work up a simple chat example.
I actually used a PHP based websocket and adapted it. I can work both ways if you want. You can store the messages sent to the websocket in an Array or even let them be saved into a database. The client can ask for new messages:
look at this code:
function createConnectionToWebSocket(connection)
{
var host = "ws://[ip of server]:9000/echobot"; // SET THIS TO YOUR SERVER --> 9000 is the port used by websockets.
try {
socket = new WebSocket(host);
console.log('WebSocket - status '+socket.readyState);
socket.onopen = function(msg) {
console.log("Welcome - status "+this.readyState);
};
socket.onmessage = function(msg) {
messageHandlerSocket(msg.data);
};
socket.onclose = function(msg) {
console.log("Disconnected - status "+this.readyState);
if (msg && !msg.wasClean && msg.code == 1006)
{
}
};
socket.onerror = function(msg) {
};
}
catch(ex){
console.log(ex);
}
}
function messageHandlerSocket(msg)
{
//all messages will be send in JSON
var msg = JSON.parse(msg)
//received JSON and check the type. Type is message
switch (msg.type)
{
case "messages" :
//code when the webserver sends back the messages.
break;
}
}
socket.send(JSON.stringify({"type" : "retrievemessages", "user" : user.id}));
Socket.send allows you to send data to the PHP server. I send JSON and parse this on the server. Based on the type argument I let the PHP server send data back to the corresponding user.
I extend this webserver I found on Github.
Run the webserver via a bat-file.
#ECHO OFF
ECHO STARTING WEBSERVER
ECHO USING [dir to php dir]\php\php.exe
#ECHO OFF
START "WEBSOCKET" /wait /B "[dir to php dir]\php\v5.6\php.exe" -f [path to your websocket.php]
So I am on a webproject that succesfully connects to and reads from an SQL database. The code that connects to it looks like this.
//From Here
var connection = new ActiveXObject("ADODB.Connection") ;
var connectionstring="Data Source=<server>;Initial Catalog=<catalog>;User ID=<user>;
Password=<password>;Provider=SQLOLEDB";
connection.Open(connectionstring);
var rs = new ActiveXObject("ADODB.Recordset");
//To Here
rs.Open("SELECT * FROM table", connection);
rs.MoveFirst
while(!rs.eof)
{
document.write(rs.fields(1));
rs.movenext;
}
rs.close;
connection.close;
Simple and effective and I have it working fine. But those first 4 (marked from here to here) run horribly slow and I have to reconnect every time I need to read from or write to the sql database... which is a lot for my project. So every time I run this code (which is on every other webpage I am creating in this project) I have to sit and wait for this code to run.
I have been told/ required for the project, to configure the design using javascript and spring framework. Apparently there is either a) a way to hold the connection so I don't have to run this code a every time I hit a go to new page or b) a different method of connection to the SQL database (something to replace those 4 lines of code. Both of which have to do with my using the Spring Framework.
I have never used Spring Framework before and need to learn fast. Been watching their website tutorials but still have no idea what to do or how to do it. Let me know if have any ideas.
Please and Thanks.
I think you got something wrong here: You aren't supposed to access your database from JavaScript because any user can access any data that way, or delete everything.
You should access the database server-side only.
You need connection pooling, which means, instead of opening and closing a new connection every time, keep the one that you were about to close, and see if you can reuse it later.
Unfortunately, I've never seen anything in JavaScript that allows you to reuse objects across pages, so there's no way afaik to do this in JavaScript. It's considered a very bad practice to connect from a browser directly to a database, anyway.
Usually, what you do is put a java or C# application server in between, and let these to the database access, using a connection pool. From your javascript, you then do an AJAX call to the application server, which will use the connection pool, and return e.g. JSON objects.
See for example http://tomcat.apache.org/tomcat-6.0-doc/jndi-datasource-examples-howto.html#MySQL_DBCP_Example