I'm trying to make a javascript program send data to a python socket but it doesn't receive the right data.
I want python to print 'aaaa'.
Here is my javascript code:
function createCORSRequest(method, url) {
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
xhr.open(method, url, true);
} else if (typeof XDomainRequest != "undefined") {
xhr = new XDomainRequest();
xhr.open(method, url);
} else {
xhr = null;
}
return xhr;
}
var xhr = createCORSRequest('GET', "http://192.168.1.10:12345");
xhr.send("aaaa");
Here is my python code:
import socket
s = socket.socket()
host = socket.gethostname()
port = 12345
BUFFER_SIZE = 1024
s.bind(('', port))
s.listen(5)
while True:
c, addr = s.accept()
print ('Got connection from', addr)
c.send(bytes('Thank you for connecting','UTF-8'))
data = c.recv(BUFFER_SIZE)
print(data)
c.close()
You are doing an XMLHttpRequest, which is a HTTP request. But your python server does not handle the HTTP protocol at all. Handling HTTP would mean to read the HTTP request header, read the body based on the information in the header and return a proper HTTP response.
You are doing a HTTP GET requests. A GET requests takes no payload so any body data you add (i.e. the "aaaa" in your xhr.send("aaaa")) will be ignored (means: not send). To send a HTTP body use request types like POST.
Steffen's answer is correct (at least in general - can't comment on the JS specifics). In addition, it's always a good idea to independently verify the moving parts of your application, so that you can narrow down where the problem is.
Here's how you can verify that your python server works from the command line:
Start the server
In another terminal window, connect to it using telnet
telnet localhost 12345
(It will first try connecting using IPv6, fail, and fall back to IPv4)
You will see your welcome message returned to the client. Enter some text and press Enter.
The server will print your message and close the connection to the client.
Using your code, here's how it will look for the client. I'm sending the text meow to the server:
margold#home-macbook ~ $ telnet 127.0.0.1 12345
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Thank you for connectingmeow
Connection closed by foreign host.
And for the server:
margold#home-macbook ~ $ ./server.py
('Got connection from', ('127.0.0.1', 61148))
meow
Related
I'm definitely a newbie with JS and node. I have telescope management software called SkyX Pro, and it has the ability to run a TCP Server on port 3040. I can connect to it using Netcat and hand it a Javascript starting with //* Javascript *// this works and allows me to startup cameras and other equipment and send commands for taking pictures etc. The issue is it needs to be run from a batch file which makes getting any information back to an HTML page tough (Like Camera, focuser and filter wheel status and temperatures).
The NC call looks like "NC localhost 3040 < Javascript-file.js
To get around the browser to local machine security issues I want to run this from node.js with maybe socket.io-client if possible, but I don't know the proper syntax for it.
I have seen plenty of client syntax sending hello's etc. but nothing send javascript and allowing for two-way connectivity that I can understand.
I have tried using:
var socket = io.connect('http://localhost');`enter code here`
socket.on('httpServer', function (data) {
console.log(data);
document.write(data + "\r\n");
socket.emit('tcp', "For TCP");
});
const net = require('net');
const client = new net.Socket();
client.connect({ port: 3040, host: process.argv[2] });
client.on('data', (data) => {
console.log(data.toString('utf-8'));
But I do not understand it well enough to troubleshoot why it's not working.
Any help would be wonderful, and please treat me like a baby that needs its step by step.
Cheer
Peter
Reading [1], We can assume socket-io isn't the perfect fit for you, because that Server you have sound like a typical tcp-socket server, not a socket.io server ( which requires special headers ) or a web-socket server.
So you only needs "net" library to do the job.
const net = require('net');
// module to send a message to TCP-socket server and wait for the response from socket-server
const sendAndReceive = async (client, message) => {
client.write(message);
let response = null
await ( new Promise( (resolve, reject) => {
client.on('data', function(data) {
response = data;
resolve()
});
}))
return response;
}
// send a single message to the socket-server and print the response
const sendJSCode = (message) => {
// create socket-client
const client = new net.Socket();
client.connect(3040, 'localhost', async function() {
console.log('Connected');
// send message and receive response
const response = await sendAndReceive(client, message)
// parse and print repsonse string
const stringifiedResponse = Buffer.from(response).toString()
console.log('from server: ', stringifiedResponse)
// clean up connection
client.destroy()
});
}
sendJSCode('var Out; \n Out="TheSky Build=" + Application.build \n\r')
This script will:
Initiate a socket client
on connection successfully, client sends a message
client receives back response from that message
client prints response to terminal
Note that TheSkyX has a limitation of 4096 bytes for each message[2], any more than that and we will need to chunk the message. So you may want to keep the js-code short and precise.
that snippet I gave is minimal, it doesn't handle errors from server. If you want, you can add client.on("error", .. ) to handle it.
Your point of connecting to the socket server directly from browser is very intriguing, unfortunately it is not allowed by modern browsers natively due to security concerns 3
[1] https://socket.io/docs/#What-Socket-IO-is-not:~:text=That%20is%20why%20a%20WebSocket%20client,to%20a%20plain%20WebSocket%20server%20either.
[2] https://www.bisque.com/wp-content/scripttheskyx/scriptOverSocket.html#MSearchField:~:text=set%20to%204096%20bytes
In my code I am trying to send a POST request to the IFTTT service webhooks (maker).
I'm using a couple of libraries, mainly WiFi101
I am using an Arduino MKR1000.
I have updated the firmware, and added a certificate for https://maker.ifttt.com:443.
When in the following code I call sslClient.connect(host, 443); It fails to make the connection. I have tried bypassing this and just trying to print data to the host, however this also didn't work.
It takes about 10-20 seconds for the function to return as false, if I change the host to an incorrect variable, then it returns as false immediately. I'm assuming this is a good sign since the arduino is trying to connect?
wifiSetup() Runs well, connection is established reasonably quickly.
The code I am refering to is below:
Globally defined
//WiFi router setup
char ssid[] = "-----"; //network SSID (aka WiFi name)
char pass[] = "-----"; //network password
int status = WL_IDLE_STATUS;
const char* host = "https://maker.ifttt.com";
WiFiSSLClient sslClient;
Wifi setup procedure: This runs without problems
void wifiSetup() {
// Check for the presence of the shield
Serial.print("WiFi101 shield: ");
if (WiFi.status() == WL_NO_SHIELD) {
Serial.println("NOT PRESENT");
return; // don't continue
}
Serial.println("DETECTED");
// attempt to connect to Wifi network:
while ( status != WL_CONNECTED) {
Serial.print("Attempting to connect to Network named: ");
Serial.println(ssid); // print the network name (SSID);
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
status = WiFi.begin(ssid, pass);
// wait 10 seconds for connection:
delay(10000);
}
printWifiStatus(); // you're connected now, so print out the status
}
The code below is the one causing problems
void sendMessage() {
if (sslClient.connect(host, 443)) {
//change this to your Maker setting from https://ifttt.com/services/maker/settings
String data = "randomdata";
sslClient.println("POST /trigger/tank_empty/with/key/bxa");
sslClient.println("Host: https://maker.ifttt.com");
sslClient.println("Content-Type: application/json");
sslClient.print("Content-Length: ");
sslClient.println(data.length());
sslClient.println();
sslClient.print(data);
sslClient.stop();
Serial.println("IFTTT request Sucessful");
}
else {
Serial.println("IFTTT request failed");
}
delay(20000000);
}
Does anyone have any solutions, or things to troubleshoot?
Thanks for your help all,
Let me know if you need any extra information.
https://maker.ifttt.com is not a valid host. A valid host is either an IP address or a domain. https:// is not a part of the domain, but an URL.
You are also missing the HTTP protocol version (HTTP/1.1), which could potentially cause problems.
const char* host = "maker.ifttt.com";
sslClient.println("POST /trigger/tank_empty/with/key/bxa HTTP/1.1");
sslClient.print("Host: ");
sslClient.println(host); // non hardcoded host header
sslClient.println("Content-Type: application/json");
sslClient.print("Content-Length: ");
sslClient.println(data.length());
sslClient.println();
sslClient.print(data);
sslClient.stop();
I want to implement Server Sent Events (SSE) using simple Java Server Socket (instead with php and/or asp).
This server will do only simple things: listening for incoming request from browser, creates a handler thread, reply the request (sending header) without closing the connection, and then, wait for user input (System.in) that will forward the messages to the client.
Of course it will be an overkill if I use J2EE library (eg. Jersey) just for doing task like that.
The source is as follow:
import java.net.*;
import java.io.*;
import java.util.Scanner;
public class Loc {
public static void main ( String[] args ) throws IOException{
ServerSocket ss = new ServerSocket(8888);
//listen to only one connection.
System.out.print("Waiting for connection...");
Socket hp = ss.accept();
System.out.println("Connected!");
BufferedReader br = new BufferedReader(new InputStreamReader(hp.getInputStream()));
String line = "";
while( br.ready() && (line=br.readLine()) != null) { //dumps request header.
System.out.println(line);
}
Thread handler = new Thread(new ClientHandler(hp));
handler.start();
try {
handler.join();
}catch(InterruptedException e){
}
System.out.println("Server stopped.");
}
}
class ClientHandler implements Runnable{
Socket toClient;
public ClientHandler(Socket s){
this.toClient = s;
}
public void run() {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //server input (also forwards it to client)
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(toClient.getOutputStream()));
// response header.
String response = "HTTP/1.1 200 OK\n"+
"Server: Maknyos-Server/1.0\n"+
"Cache-Control: no-cache,public\n"+
"Content-Type: text/event-stream\n"+
"Connection: keep-alive\n"+
"Language: en-US\n"+
"Charset: UTF-8\n"+
"\n"; //two line break as header ending.
bw.write(response);
bw.flush();
String input = "";
while ( (input = br.readLine()) != null ) { //one directional message to client (browser), via cmd.
bw.write(input+'\n');
bw.flush();
if("close".equalsIgnoreCase(input)){
break;
}
}
toClient.close();
}catch(IOException e){
System.out.println("IOEXception! "+e);
}
}
This is the client.
<h1>Hullo World!</h1>
<script type="text/javascript">
var es = new EventSource("http://localhost:8888");
es.onmessage = function (event) {
alert(event.data);
};
</script>
When I open the html page, I can see the http request header on my server std out (command line).
My server then reply it with
HTTP/1.1 200 OK
Server: Maknyos-Server/1.0
Cache-Control: no-cache,public
Content-Type: text/event-stream
Connection: keep-alive
Language: en-US
Charset: UTF-8
...
I'll try to describe what I do and what is the problems, between those two client and server. It maybe related to the protocol, but I'm not sure.
First, If I put only two (new line) at the end of the header to finish the response header (as the example above), Firefox console will tell me that the browser can't connect to the server. But, in the NET console, it receives the response request.
Second, I test without finishing the response header (without double \n character).
Neither of them succeeded in sending SSE to the browser.
Edit, when I see again the browser's console windows, it appears that It cannot make a request to another domain!
this program runs on localhost:8888
but the webserver I use (for the html page) is on localhost:80
I suggest you write your application using Spring Boot and write a controller which will return an instance of SseEmitter. Spring Boot is lightweight and fits your requirements.
http://docs.spring.io/autorepo/docs/spring-framework/4.3.0.RC2/javadoc-api/org/springframework/web/servlet/mvc/method/annotation/SseEmitter.html
Remember to use the send() method in another thread.
It turns out that I'm missing one important header in my server header string.
"Access-Control-Allow-Origin:*" + "\r\n" + ...
How can I receive multiple responses from a server using javascript.
I have a requirement where a request is posted one time with the data and number of iterations and at server side the request is processed for the number of iterations. On completion of each iteration the server sends back the response. So for one request and 10 iterations my java script need to receive the 10 responses and show it on the web page. Is there any way that I can handle this using javascript. I cannot use any other technology.
Right now I am using the following way
function showResponse(){
xmlHttp = GetXmlHttpObject();
var dataString = document.getElementById("request-parameters").value;
var iterations = document.getElementById("iterations").value;
if(xmlHttp==null){
alert("your browser does not support AJAX!");
}
var url = "http://localhost:8080/servlet/requestServlet";
xmlHttp.onreadystatechange=stateChanged;
xmlHttp.open("POST",url,true);
xmlHttp.send(dataString);
}
function GetXmlHttpObject(){
var xmlHttp=null;
try{
//Firefox, Opera, Safari
xmlHttp=new XMLHttpRequest();
}catch(e){
//IE
try{
xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
}catch(e){
xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
}
}
return xmlHttp;
}
function stateChanged(){
if(xmlHttp.readyState==4){
if(xmlHttp.status == 200){
var resp = xmlHttp.responseText;
var responseDiv = document.getElementById("response");
responseDiv.innerHTML=responseDiv.innerHTML+resp1[1];
}
}
}
I cannot modify this approach. Is it possible to get it done with XmlHttp object.
With just 'basic javascript' you cannot do this.
It just works like this: Client sends request, servers returns 'something'. The server cannot simply keep sending data back to this client for multiple reasons. A: There is not a 'link' aka connection between both party's except for the first 'call' of a request, but the client just waits for the response.
B: The script does not expect an other answer back.
What you need is a websocket for example. This way the client can listen to the server and actually process data send from the server to the client.
So in short:
Javascript works always like this:
Client -> Server | and the server respond back
For a socket you can have:
Client -> Server
Server -> Client
You can use some sort of 'javascript' even tho its a different technology.. like NodeJS.
The other way is to make a loop. Rather than posting a dataset with an amount of iterations, just iterate it in JS and for each iteration send it to the server to actually 'perform' on your data.
1) HTTP Try request once to one controller, and then get answer from other controller, you can do this with jQuery or with native XmlHttpRequest (it is not one request).
$.get("server/controllerJob",{data:"data"});
var askInterval = window.setInterval(function(){
$.get("server/askAnswerFromJob",{data:"data"}).done(function( data ) {
if(data.complete){
/** do staff**/
window.clearInterval(askInterval);
}else{
/** do staff**/
}
});
},200);
2) webSocket Or try to find something about WebSocket webSocket documentation, it is techonolgy with one connection with multiple request and response (full-duplex connection stream).
Also you need other server controller realization and see websocket
supported browsers
Notice the ws:. This is the new URL schema for WebSocket connections.
There is also wss: for secure WebSocket connection the same way https:
is used for secure HTTP connections
I'm only just noticing that the "examples" web app that comes with
Tomcat 7 contains 4 complete examples of how to use WebSocket (for java developers)
var connection = new WebSocket('ws://server/yourService',['soap','xmpp']);
connection.onopen = function () {
connection.send('ask'); // Send the message to server
};
//Each time on new messages from server, this callbacks will be executed (depends on result)
// Log errors from server
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
};
// Get messages from the server
connection.onmessage = function (e) {
console.log('Answer: ' + e.data);
};
After toying around with this for hours, I simply cannot find a solution. I'm working on a WebSocket server using "node.js" for a canvas based online game I'm developing. My game can connect to the server just fine, it accepts the handshake and can even send messages to the server. However, when the server responds to the client, the client doesn't get the message. No errors, nothing, it just sits there peacefully. I've ripped apart my code, trying everything I could think of to fix this, but alas, nothing.
Here's a stripped copy of my server code. As I said before, the handshake works fine, the server receives data fine, but sending data back to the client does not.
var sys = require('sys'),
net = require('net');
var server = net.createServer(function (stream) {
stream.setEncoding('utf8');
var shaken = 0;
stream.addListener('connect', function () {
sys.puts("New connection from: "+stream.remoteAddress);
});
stream.addListener('data', function (data) {
if (!shaken) {
sys.puts("Handshaking...");
//Send handshake:
stream.write(
"HTTP/1.1 101 Web Socket Protocol Handshake\r\n"+
"Upgrade: WebSocket\r\n"+
"Connection: Upgrade\r\n"+
"WebSocket-Origin: http://192.168.1.113\r\n"+
"WebSocket-Location: ws://192.168.1.71:7070/\r\n\r\n");
shaken=1;
sys.puts("Handshaking complete.");
}
else {
//Message received, respond with 'testMessage'
var d = "testMessage";
var m = '\u0000' + d + '\uffff';
sys.puts("Sending '"+m+"' to client");
var result = stream.write(m, "utf8");
/*
Result is equal to true, meaning that it pushed the data out.
Why isn't the client seeing it?!?
*/
}
});
stream.addListener('end', function () {
sys.puts("Connection closed!");
stream.end();
});
});
server.listen(7070);
sys.puts("Server Started!");
Here's my client side code. It uses Chrome native WebSockets.
socket = new WebSocket("ws://192.168.1.71:7070");
socket.onopen = function(evt) {
socket.send("blah");
alert("Connected!");
};
socket.onmessage = function(evt) {
alert(evt.data);
};
var m = '\u0000' + d + '\uffff';
var result = stream.write(m, "utf8");
Ah, that seems not quite right. It should be a zero byte, followed by a UTF-8 encoded string, followed by a 0xFF byte.
\uFFFF does not encode in UTF-8 to a 0xFF byte: you get 0xC3 0xBF. In fact no character will ever produce an 0xFF in UTF-8 encoding: that's why it was picked as a terminator in WebSocket.
I'm not familiar with node.js, but I would guess you'd need to say something like:
stream.write('\u0000'+d, 'utf-8');
stream.write('\xFF', 'binary');
Or manually UTF-8 encode and send as binary.
The handshaking is also questionable, though I guess it's a simple-as-possible first draft that's probably working for you at the moment. You're relying on the first packet being the whole handshake header and nothing else, then the second packet being the payload data. This isn't at all guaranteed. You'll probably want to collect data in a buffer until you see the 0x0D 0x0A 0x0D 0x0A marker for the end of the headers, then check the header content and possibly return the 101, then continue from data after that marker.