Sending Message from TCP server in erlang - erlang

I have just started off on Erlang. I want to create a TCP server in Erlang. My TCP client runs on Android and connects to the server.
I have taken the TCP server implementation from
https://github.com/kevinlynx/erlang-tcpserver
I am able to run the server, connect the client to it and send messages from the client to the server. Also, the logic in the server is that whenever it receives a messages from the client, it sends back the same message to the client.
All this works fine, my only problem is how do I send a message to client from the erlang shell(without having to wait for a message from client). The gen_tcp:send() function requires as input the Socket handle, whenever client sends a message, there is a callback and it has the socket handle so it can be used to send message back to the client, but how to do it otherwise?

On the server side, you must be accepting the connection somewhere:
{ok, Sock} = gen_tcp:accept(LSock)
And I suppose you could send a message to that socket:
gen_tcp:send(Sock, YourPacket)
If you do not accept connections then it is not a server.
Updating to answer comment
One way is sharing the listener socket (LSock in the example). You could save it on an accessible ETS and call the acceptor from the shell despite it not been the owner of the listener.
Otherwise you are going to have to wrap everything on a server where you keep the opened socket/s in a State, and program a handle to send messages to opened sockets. A nice explanation of a socket server can be found here.

I have just started off on Erlang. I want to create a TCP server in Erlang.
I think the problem is that you are using software that sets up a communication channel between a client and a sever:
(client) ================== (server)
Now you have a third entity:
(client) ================== (server)
(erlang shell)
and you want the erlang shell to communicate with the client. That's all well and good, but the code you are using doesn't provide for that. It sounds like you also want your client to act as a server for the erlang shell. Why do you need the erlang shell to send messages to the client?
The erlang shell could become a second client of the server:
(client) ================== (server)
(erlang shell) ============ (server)
but that doesn't help the erlang shell communicate directly with the client. The erlang shell could send some information to the sever, and the server could store that information in the State, then the server could pass the State to the client the next time the client made a request.
If the erlang shell had the Pid of the client, the erlang shell could always do:
Pid ! "hello client"
and if the client were waiting in a receive-statement, then the client could extract that message from its mailbox. What does your client look like?

Related

Spring Web Socket not broadcasting message to all application servers

I am trying to setup load balanced environment having 2 application server instances. I am unable to make spring web socket relay messages to all instances. Let's take a example to describe my problem better:
Server 1 : Responsible for job executions and 35% user load.
Server 2 : 100% user load.
Both are connected to same database schema so job request can come for any server instance but will get executed on Server 1.
Now, I have used spring web socket plugin for my GRAILS application and I push messages to browser using
brokerMessagingTemplate.convertAndSend(user.notificationChannel, ((notification.toMap(user) as JSON)).toString())
It was working fine on single server setup. But on multi-server setup,
notifications are only received on Server 1 as that is the one calling the code block, if reverse the scenario, then vice-versa result is observed.
How can I push same notification to all server instances, so that user always gets the notification no matter what server instance he is on?
I initially thought of utilising a common queue like RabitMQ but that will add to system requirements and will get disapproved by client.
NOTE: Third party service solutions won't work in my case as applications are on intranet and don't have internet access.
websockets by default point to a hostname/ip address - whilst you could setup a dns record / hostname that points to multiple different ip's / servers. This itself would break communication flow of the websockets if it sent handshake to one and the message to another.
The most simplest approach would be to think of some db table that is shared across both and as each instance comes up/alive it records its local ip / socket port to a db table - each instance can then read this table and work out at any point which are the hosts to transmit a socket message to - (this table would need to managed somehow - upon a brand new bootup ) it would be empty and would popuplate as instances came up - something again to manage when a host is taken down shutdown.
Each instance would then be running an ws internal client. When a message is sent the ws client would be triggered attempting to find all alive websocket servers "from the db" to each using the ws client it would attempt to connect and send the message on. Each would then get the message and either broadcast to all connected users or if it is from user x meant for user x then like per chat plugin it would relay it only to user x if found on server y and so on.
this then keeps it all inline with 1 technology controlling the entire process websocket server that has its own client which relay to the end multiple instance ws socket server

Pre-authentication steps in ejabberd

I am working on a project like whatsapp and using ejabberd as a backend server with Android/IOS clients. I want to do some whatsapp like step-
1. Client sends mobile number to server.
2. server sends OTP in return to the client and starts a timer say 2 minutes.
3. If client sends correct OTP, received from the server, to the server within the time specified. Client will be registerd.
I need help in which ejabberd module should I write the code of above steps. I know, to modify Ejabberd I can use Hooks and IQ handlers, but they can be used once the user is already registered. Right?
Should I use other language server, just for the above steps? Please help.
You should write new ejabberd module which starts a new SSL server on a specific port. Do your authentication on that.
If you are familiar with ejabberd's core, you can add your own module in listen part of config and write new module as backend of your server (same as ejabberd itself which wrote ejabberd_c2s, ejabberd_service, etc).
I just read its code and i recommend to read the code too.
For example in ejabberd version 17.01 here reads config and runs a tcp server for every section of listen key. every section has three parts Port, Module and Opts. For xmpp clients of ejabberd these are 5222, ejabberd_c2s and Opts is other values. in here for every accepted connection it calls ejabberd_socket:start(Module, gen_tcp, Sock, Opts). In ejabberd_socket:start/4 here starts a process say A for receiving from socket and parsing XML and send them to another process say B and here starts a process (B) from ejabberd_c2s. Process B receives XMLs from Process A and does all actions off XMPP clients in ejabberd.
I think you should create a restful service to do this.
Please consider following steps:
Client sends mobile number to restful service.
The restful service create a OTP and save it in Redis with expired is set.
The client sends OTP to restful service. If the OTP is correct, service sends a jwt Token to client and save it in Redis with expired is set.
The client sends jwt token to eJabberd server and the server authenticates with ejabberd_auth_jwt module.
This may meet your requirement.

Using Yaws and websockets to subscribe to data

I have a gen_server speaking to several hardware sensors. This setup works fine. Now I want to extend this system with a real time visualization of the data. And I want to deliver this data to a web client over websockets.
As I might have several "listeners", e.g. several people visualizing this data on different web browsers, I am thinking of something resembling the Observer Pattern. Each time a web client asks to subscribe to a sensor, it should be added to a list of stakeholders for that sensor. As soon as new sensor data arrives, it should be pushed out to the client without delay.
I am using yaws to quickly get websocket functionality. My problem is related to the way that yaws seems to work. On the server side I only "see" the client at connection time through the A#arg.clisock value (e.g. #Port<0.2825>). In the code below I register ws_server to receive the callbacks when new data enters from the client. After this point yaws seems to only allow me to respond to messages entering server side.
out(A) ->
CallbackMod = ws_server,
Opts = [{origin, "http://" ++ (A#arg.headers)#headers.host}],
{websocket, CallbackMod, Opts}.
This is what the callback module looks like:
% handle_message(Incoming)
% Incoming :: {text,Msg} | {binary,Msg} | {close, Status, Reason}
handle_message({Type,Data}) ->
gen_server:cast(?SERVER,{websocket,Data}),
noreply.
Nowhere, it seems, am I able to react to a message such as subscribe <sensor> and (after connection time) dynamically add this stakeholder to a list of observers.
How can I use the yaws server to accomplish asynchronous pushing of data to client and during session add and remove sensors that I want to listen to. Basically the easiest way would be if yaws could call back handle_message/2 with first argument being From. Otherwise I need to add a ref to keep a ref on both sides and send that to server each time, it seems backwards that I need to keep that information.
When the client starts a websocket connection Yaws will start a new gen_server process to handle all communication between client and server.
The gen_server dispatches all client-sent messages to your callback function handle_message/1, so it is not used only for the initial connect.
Also, the gen_server process is used to push data from the server to the client - use the yaws_api:websocket_send(Pid, {Type, Data}) function. The Pid parameter is the pid of the websocket gen_server. Your callback module could be changed to:
handle_message({Type,Data}) ->
gen_server:cast(?SERVER,{self(), Data}),
noreply.
This gives your server the pid of the websocket gen_server to be used with yaws_api:websocket_send/2. The Data parameter contains the client request and needs to be parsed by your server to check for sensor subscription requests and associate the websocket pid with the appropriate sensor.

How does a HTTP response find its way to the correct browser window?

If you have two browser windows open and you use each to navigate to a different website, then how does the software know which HTTP response belongs to which browser instance?
Update
It seems that the distinction is made by the inbound TCP port numbers. But what about network messages that don't involve TCP/UDP? For example, if you open two terminal applications and use both send a ping message to the same remote server, how does the reply find its way to its terminal instance?
Typically, each browser instance creates its own socket to communicate with the server. Though the outbound port of all the sockets is the same (usually TCP 80 or 443), their inbound ports are different. Thus, there are no conflicts when the server responds to the requests, since the responses are sent to different inbound ports.
Tools like ping use ICMP packets, which provide their own way to uniquely identify the calling application (a unique identifier and a sequence number).
They're usually associated with different TCP connections, which between them have used different ports on the client end. This means that the TCP stack at the client end knows the different and passes them via the sockets API the client used in an easily distinguishable way. (Typically different file descriptors)
The exception to this is pipelining where multiple http request can be sent over one connection, as an optimisation. Requests sent like this are received in the order they were sent however, making it trivial to match them to the requests.

how can i manage connections in Indy ? (Delphi)

i am writing a simple client/server chat program with indy 10 (blocking mode) and there is a question that how can i manage connections ?
for example imagine a user that is online on server , we must make a connection tunnel for future requests . In other words, when a user is online server should not need username and password for future user requests . and it will be do with the tunnel that we created when user has came .
how can we manage connections ?
[sorry for my bad english] if you can't understand me please tell me to send a new post agian .
Thank you
For the scenario described in the question, there isn't really much management to do. To avoid having to re-authenticate on every request, simply don't close the connection. In a chat server, especially, it's quite likely that each participant will establish a connection and then continue using that same connection for the duration of the chat.
Indy server objects already keep a list of their open connections, so when you want to broadcast a chat message to the other participants, you can just iterate over that list.
I think 100000 checks per second will be the less resource consuming thing, than having 10000 persistent TCP connections. And anyway you will need to process somehow these 100000 commands, so those checks would not be the bottleneck.
Try to use the UDP messages instead. For example, most MMO games use both TCP and UDP connections. TCP only for critical data, and UDP for any other data. In your case UDP seems to be acceptable. The client can send UDP packets with some autoincrement IDs, and the server can periodically send back the list of IDs it doesn't receive, so the client can resend them.
One option would be to create a unique session ID (or "token") on the server side, for example a GUID, if a client logs in. And in every request, the client includes this token.
The server would maintain a list of client sessions and associated session data, and looks up the token in this list.
Even if a client is temporary disconnected from the Internet but still knows its token, the application can reconnect and continue the session with the server.

Resources