I have a server written in python and an Android client written in Kotlin (in Android Studio IDE). I use sockets for maintaining this connection. After the client sends a message to the server, the server will need to send an answer to the client. I didn't find a way to receive data at the client by using sockets. I tried to do that:
var server = Socket(serverIP, serverPort)
server.outputStream.write(message.toByteArray())
var answer = server.inputStream.bufferedReader().use(BufferedReader::readText)
server.close()
but it seems not to work. If it matters, the sending at server side looks like that:
client.send(message.encode())
I suppose, you are using OkHttp for this. In my app I have the following code
private fun getClient(): OkHttpClient {
return try {
val builder = OkHttpClient.Builder()
builder.pingInterval(30, TimeUnit.SECONDS)
builder.build()
} catch (e: Exception) {
throw RuntimeException(e)
}
}
class WebSocketController(
val callback: SomeCallback
) {
private val url = "wss://your.url.com/"
private val socketClient = getClient()
private var serverSocket: WebSocket? = null
private val listener = object : WebSocketListener() {
override fun onOpen(webSocket: WebSocket, response: Response) {
super.onOpen(webSocket, response)
val json = "" // your payload to send on connect
serverSocket = webSocket
serverSocket!!.send(json)
}
override fun onMessage(webSocket: WebSocket, text: String) {
super.onMessage(webSocket, text)
val data = Json.decodeFromString<YourModel>(text)
// here you can use your data from server
callback.makeSomething(data)
}
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
super.onFailure(webSocket, t, response)
callback.onFailure(t)
}
}
fun establishConnection() {
socketClient.newWebSocket(requestBuilder().build(), listener)
}
fun disconnect() {
val json = "" // your payload on disconnect
serverSocket?.send(json)
}
private fun requestBuilder(): Request.Builder = Request.Builder().url(url)
}
Related
I'm making just for study, an API.
I want communicate one with other, my map for the problem is.
Using PyQt, develop a interface to instance a object with some attributes.
In the same time, open the navigator in the Node API(localhost:4100/ts)
I want communicate per example(1 letter typed on Python, change on the Node/client.
Node Api
class Server{
...
run(){
this.app.get("/ts",async(req,res) =>{
const user = await this.query()
res.render("ts",user)
})
this.app.use(express.static(__dirname))
const httpServer = http.createServer(this.app)
httpServer.listen(this.port, () =>{
console.log(`app listening on ${this.port}`);
})
}
async query(){
const b = 'user-signature'
const options = {
method: "POST",
body:JSON.stringify(b)
}
const uri = this.url+"mail"
try{
const postrequest = await fetch(uri,options)
const response = await postrequest.json()
return response
}
catch{
return new Mail('Name','LastName','Phone','Office','Sector','Email')
}
}
}
Python API
#app.route('/py/mail', methods=['POST'])
def mail():
print('initing')
data = request.get_data()
req = json.loads(data)
user = {
"first_name":input("Nome:"),
"last_name":input("Sobrenome:"),
"phone":input("Telefone:"),
"job_title":input("Cargo:"),
"en_job_title":input("Cargo em Inglês:"),
"mail":input('Email:'),
#"image_url":'https://www.ayrtonsenna.com.br/wp-content/uploads/2020/09/THUMBNAIL_SENNA_0420200903-3890-wlwakh.jpg'
}
The postrequest communicate with the python, but just one time, after that the callup end. It's possible make a constant communication between Node and Py? Like a listener?
Sometimes it crashes after 54 seconds, sometimes 56 seconds. Output looks like:
Server started. Listening for incoming connections...
55 Received message: hello server
1/12/2023 7:38:25 AM|Fatal|WebSocket.<startReceiving>b__176_2|System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Sockets.NetworkStream'.
at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
at WebSocketSharp.Ext.<>c__DisplayClass48_0.<ReadBytesAsync>b__0(IAsyncResult ar)
I tried to add a try/catch block but I am not sure where the error is happening. I am running a websocketsharp server in c# and sending it sample data via python:
C# SERVER CODE:
using System;
using WebSocketSharp;
using WebSocketSharp.Server;
public class Echo : WebSocketBehavior
{
protected override void OnMessage(MessageEventArgs e)
{
try {
Console.WriteLine("Received message: " + e.Data);
Sessions.Broadcast(e.Data);
}
catch{
Console.WriteLine("bad happened");
}
}
}
public class Program
{
public static void Main(string[] args)
{
var wssv = new WebSocketServer(8081);
wssv.AddWebSocketService<Echo>("/Echo");
wssv.Start();
Console.WriteLine("Server started. Listening for incoming connections...");
Console.ReadLine();
wssv.Stop();
}
}
PYTHON CLIENT CODE:
import time
import websocket
def send_words(ws,words):
data = words
ws.send(data)
ws = websocket.create_connection("ws://localhost:8081/Echo")
while True:
time.sleep(1)
data = "hello server"
send_words(ws,data)
apparently its a websocket-sharp specific issue. You just have to add
wssv.KeepClean = false;
before
wssv.Start();
I am new to angular and i want to display JSON data from python to angular with the help of node.js and I used child process to connect python and node.js but I dont know how to pass it to angular service
node.js file
const express = require('express')
const { spawn } = require('child_process')
const app = express()
const port = 8000
app.get('/', (req, res) => {
let dataToSend
let largeDataSet = []
// spawn new child process to call the python script
const python = spawn('python', ['test.py'])
// collect data from script
python.stdout.on('data', function (data) {
console.log('Pipe data from python script ...')
//dataToSend = data;
largeDataSet.push(data)
})
// in close event we are sure that stream is from child process is closed
python.on('close', (code) => {
console.log(`child process close all stdio with code ${code}`)
// send data to browser
res.send(largeDataSet.join(''))
})
})
app.listen(port, () => {
console.log(`App listening on port ${port}!`)
})
Technically you just have to send a Http GET request from your service.
I suggest that you should read and follow this offical http client guide to set it up correctly.
Here is a simple service snippet. This should be enough.
#Injectable({
providedIn: 'root',
})
export class MyService {
constructor(private http: HttpClient) {}
getData(): Observable<any> {
const url = '';
return this.http.get(url);
}
}
I've set up a websocket in AWS using API gateway and a simple lambda function shown below:
import json
import boto3
def lambda_handler(event, context):
route = event["requestContext"]["routeKey"]
connectionId = event["requestContext"]["connectionId"]
client = boto3.client('apigatewaymanagementapi',
endpoint_url='https://testid.execute-api.ap-southeast-2.amazonaws.com/production')
if route == "$connect":
print('Connection occured')
elif route == "$disconnect":
print("Disconnected")
elif route == "message":
print("Message received")
api = client.post_to_connection(
Data=json.dumps({'result': 'success'}),
ConnectionId = connectionId
)
return {
'statusCode': 200,
'body': json.dumps('Hello from Lambda!')
}
In flutter I connect to the websocket on startup using the web_socket_channel package (skipped some boilerplate code for simplicity)
import 'package:web_socket_channel/io.dart';
#override
void initState() {
super.initState();
WidgetsBinding.instance?.addPostFrameCallback((_) async {
channel = IOWebSocketChannel.connect('wss://testid.execute-api.ap-southeast-2.amazonaws.com/production');
channel.stream.listen((message) {
print(message);
});
}
}
When I check the AWS lambda logs I can see that a connection was definitely established.
I then use a button to trigger a function that sends a message to the message route.
void sendMessage(){
channel.sink.add({'action':'message'});
}
On running the sendMessage function, nothing happens and the connection gets disconnected. I'm actually not sure if that's the way to send a message to a custom route as I couldn't find anything in the docs for the web_socket_channel package. How can I get this working so that the connection stays alive and receives messages from the lambda?
Oh solved it. I just needed to send the json as a string.
void sendMessage(){
channel.sink.add(jsonEncode({'action':'message'}));
}
I have written an application which is nodejs (main app) and python (client) app that i want to communicate with each other using zmq Router,Dealer pattern.
the problem is i could not read the messages sent from clients to nodejs (router) app.
its encoded some how.
the code is as simple as below:
var responder = zmq.socket('router');
responder.on('message', function(request) {
console.log(request);
// i could not read the messages here.its obfuscated
});
responder.bind('tcp://127.0.0.1:8000', function(err) {
if (err) {
console.log(err);
} else {
console.log('Listening on 8000...');
}
});
python:
socket = context.socket(zmq.DEALER)
socket.connect("tcp://127.0.0.1:8000")
socket.send('blaaaa')
print 'message sent!'
If you wish to use the DEALER/ROUTER sockets, then the message is actually given as the second argument for the callback function.
var responder = zmq.socket('router');
responder.on('message', function(header, body) {
console.log(body.toString('utf8'));
});
The message is in the format of a Buffer, but you can turn it into a string using .toString(encoding);
The header contains an identity, this allows you to later route the response/answer back to the correct sender/requester that made the original request.
For your application, PUSH-PULL seems more appropriate:
var zmq = require('zmq');
var responder = zmq.socket('pull');
responder.on('message', function(request) {
console.log(request.toString());
// Use `toString` to convert Buffer to string
});
responder.bind('tcp://127.0.0.1:8000', function(err) {
if (err) {
console.log(err);
} else {
console.log('Listening on 8000...');
}
});
import zmq
context = zmq.Context()
socket = context.socket(zmq.PUSH)
socket.connect("tcp://127.0.0.1:8000")
socket.send('blaaaa')
print 'message sent!'