I'm new to the subject area so sorry If I've not explained things well.
I created a web API client that sends strings from my HTML (imbedded with JavaScript) back to a node.js server using Web Sockets.
I then swapped out the node.js server with a C++ application that still receives the string data perfectly.
My JS Client(within html script) :
function SendWSData(){
const ws = new WebSocket("ws://localhost:PORT");
ws.addEventListener("open", () => {
console.log("We are connected!");
const stringvalue = `this is a test string`
ws.send(stringvalue);
});
ws.addEventListener("message", ({ data }) => {
console.log(data);
});
}
My C++ Server:
#include <boost/beast/core.hpp>
#include <boost/beast/websocket.hpp>
using namespace std;
using tcp = boost::asio::ip::tcp;
string stringVal;
int main() {
auto const address = boost::asio::ip::make_address("IP");
auto const port = static_cast<unsigned short>(std::atoi("PORT"));
boost::asio::io_context ioc{1};
tcp::acceptor acceptor{ioc, {address, port}};
tcp::socket socket{ioc};
acceptor.accept(socket);
std::cout<<"socket accepted"<<std::endl;
std::thread{[q = std::move(socket)]() mutable {
boost::beast::websocket::stream<tcp::socket> ws {std::move(q)};
ws.accept();
while(1)
{
boost::beast::flat_buffer buffer;
ws.read(buffer);
auto out = boost::beast::buffers_to_string(buffer.cdata());
stringVal = out
std::cout<<"stringVal = "<<stringVal<<std::endl;
}
}
This reads data coming into the buffer, and assigns it to a string variable on my C++ app, for me to use.
My question is how would I go about sending back a string to the web page from the C++ app? (especially as my web page is the client and the C++ app is the server)
I know that the server is meant to return a response which is standard, however does that change if I'm trying to implement a function based response? I want to generate a button on the webpage and textbox, and when clicked I get string data from the C++ app.
I've not found much online about sending data from server back to client, as I'm trying to get a request (which is the behaviour of a client). (Could I possibly generate another Web Socket and swap the roles of my web API and C++ app for this particular case; possibly multithreading it?)
Related
I am trying to read value received from JavaScript WebSocket using Java
I have this JavaScript code:
const socket = new WebSocket("wss://localhost:7999"); // start
socket.addEventListener("open", (event) => {
socket.send("Hello!");
});
socket.addEventListener("message", (event) => {
console.log("Received message.");
});
And this Java code:
import java.io.*;
import java.net.*;
class Server {
public static void main(String[] args) throws Exception {
ServerSocket s = new ServerSocket(7999);
Socket client = s.accept();
System.out.println("I am in!");
InputStream inputStream = client.getInputStream();
InputStreamReader reader = new InputStreamReader(inputStream, "UTF-8");
BufferedReader in = new BufferedReader(reader);
String readLine;
while ((readLine = in.readLine()) != null) {
System.out.println(readLine);
}
}
}
However, upon launching the server and client code, I am receiving this value:
I am in!
���
�.isֿ���pO?��-4/P�P����- ���Q�`�:���x���wG�Z��x��v�##�6���,�+̩�0�/̨�$�#�
� �(�'����=<5/�
}�� localhost�
��http/1.1
3+)�� �-l-h������ۥ n�}�>�zUZ�Ğ�-+
My goal is to read the value Hello, that I have sent using socket.send.
Does anyone know how to fix this problem?
Thanks.
ServerSocket is quite low level construct for handling TCP connections.
Websocket even though it starts as an HTTP request it requires server to request connection upgrade, there is handshaking, then handling websocket frames, including some internal frames like ping/pong.
Unless you plan to implement that entire functionality, I'd suggest you to not use raw ServerSocket but instead use a library that provides websocket support out of the box.
Some options that I could point you to are:
netty
vert.x
Scenario
C# Based Server
JavaScript Based Client
Situation
I created this fairly simple "server" which only job is to help me understanding how to actually use those websockets in a C# environment.
using (var server = new HttpListener())
{
server.Prefixes.Add("http://localhost:8080/");
server.Start();
while(true)
{
var context = server.GetContext();
if (context.Request.IsWebSocketRequest)
{
var cntxt = context.AcceptWebSocketAsync(null).ConfigureAwait(true).GetAwaiter().GetResult();
var buff = new byte[2048];
while(cntxt.WebSocket.State == System.Net.WebSockets.WebSocketState.Open || cntxt.WebSocket.State == System.Net.WebSockets.WebSocketState.Connecting)
{
cntxt.WebSocket.ReceiveAsync(new ArraySegment<byte>(buff), CancellationToken.None).ConfigureAwait(true).GetAwaiter().GetResult();
Console.WriteLine(Encoding.UTF8.GetString(buff));
}
}
else
{
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
using (var writer = new StreamWriter(context.Response.OutputStream))
{
writer.Write("<html><body>WEBSOCKET ONLY!</body></html>");
}
}
}
}
The problem now is: when i try to add the websocket prefix via server.Prefixes.Add("ws://localhost:8080"), i get some System.ArgumentException thrown which tells my i can only add http and https as accepted protocol.
Thing is: doing it and using ws = new WebSocket('ws://localhost:8080'); (JavaScript) to connect to a websocket, yields for obvious reasons nothing.
Changing the prefix to HTTP in the JS websocket, will provide me with yet another sort-off argument exception.
Actual Question
how to actually get the HttpListener to acceppt web socket requests?
Further Info
Used .net framework is 4.6.1
Browser to test this was Google Chrome 69.0.3497.100
The reason for why the above was not working ... is due to the JS websocket requiring a path.
Changing the above HttpListener prefix to eg. "http://localhost:8080/asdasd/" will allow the socket to connect propertly.
I'm attempting to write a C# WebSocket server for an application that interacts upon browser input.
This is the code:
class Program {
static void Main(string[] args) {
var listener = new TcpListener(IPAddress.Parse("127.0.0.1"), 42001);
listener.Start();
using(var client = listener.AcceptTcpClient())
using(var stream = client.GetStream())
using(var reader = new StreamReader(stream))
using(var writer = new StreamWriter(stream)) {
while (!reader.EndOfStream) {
String line = reader.ReadLine();
if (new Regex("^GET").IsMatch(line)) {
line = reader.ReadLine();
if (new Regex("^Sec-WebSocket-Key: ").IsMatch(line)) {
String key = new Regex("(^Sec-WebSocket-Key\\: |\\r\\n)").Replace(line, "");
key = Convert.ToBase64String(SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")));
writer.WriteLine("HTTP/1.1 101 Switching Protocols");
writer.WriteLine("Upgrade: websocket");
writer.WriteLine("Connection: Upgrade");
writer.WriteLine("Sec-WebSocket-Accept: " + key);
writer.WriteLine("Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits");
writer.WriteLine("WebSocket-Origin: http://127.0.0.1");
writer.WriteLine("WebSocket-Location: ws://localhost:42001/websocket");
writer.WriteLine("");
}
}
}
}
listener.Stop();
}
}
... and:
var ws = new WebSocket('ws://localhost:42001/websocket');
ws.onopen = function() {
console.log('connected');
};
ws.onmessage = function(e) {
console.log(e.data);
};
ws.onerror = function(e) {
console.log(e);
};
ws.onclose = function() {
console.log("closed");
};
On execution, the TPCListener successfully accepts the TCPClient and reads the incoming HTTP request. It parses the Key, generates the correct Accept token, but the JS - window native - WebSocket seems to have gone flat out bonkers: it does not answer no matter what it receives.
I would expect it throwing an error upon sending a HTTP/1.1 400 Bad Request, but nothing at all happens. It just goes mute.
Checking out Chrome Dev Tools' Networking tab, I do only see the websocket outgoing GET request, but no incoming packets - is that supposed to happen?
If I forcefully close the application, WebSocket throws this exception:
WebSocket connection to 'ws://localhost:42001/websocket' failed: Error during WebSocket handshake: net::ERR_CONNECTION_RESET.
What am I missing here? Thank you all in advance.
Also, I'm not using Net.WebSockets because it is available since .NET 4.5, and my application targets systems from Windows 7 to the current build of Windows 10.
well... how far does your C# code get? My first bet would be on buffering - you don't flush the writer or stream, so I would expect them to be holding onto data while stuck in the top of the while loop, but frankly it shouldn't be a while loop in the first place - you only get one handshake per socket, not many. You could try adding flushes after the blank line, and you should make sure the Socket itself has buffering disabled (NoDelay = true;) - but: fundamentally this isn't a good way to write a web-socket server. Apart from anything else, the data will cease to be text if the handshake succeeds, so having a TextReader is a very bad thing. Frankly, you should be dealing with raw Socket / byte[] data here, IMO (having implemented this very thing several times).
For example it needs to call a web service hosted with SSL.
If it can, how to pass the client certificate then?
Thanks a lot!!
WinJS.xhr({
type: "GET",
url: "https://localhost:442/WebService1.asmx?op=Login",
}).then(function success(res) {
var debug1 = res.responseText + res.responseURL;
}, function error(err) {
var debug2 = err.responseText + err.responseURL;
}, function completed(result) {
if (result.status === 200) {
// do something
}
});
The debugging point will jump to 'complete(result)' function, but the status code is '0'. Even if I change URL to other https site (e.g. https://www.w3.org), result is the same.
------------- Update 1 ---------------------
If it's in C# I could use following code to pass client certificate. However if I want to change origial WinJs.xhr to HttpClient, just copy & paste seems not working as .js file could not understand all syntax?
var certQuery = new CertificateQuery();
var cert = (await CertificateStores.FindAllAsync(certQuery)).FirstOrDefault(c=>c.Issuer.StartsWith("xxxx",StringComparison.CurrentCultureIgnoreCase));
var filter = new HttpBaseProtocolFilter();
if (cert != null)
{
filter.ClientCertificate = cert;
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted | ChainValidationResult.InvalidName);
}
var hc = new Windows.Web.Http.HttpClient(filter);
var uri = new Windows.Foundation.Uri(url);
hc.getStringAsync(uri).done({.......});
E.g.
1) How to write 'Using .... ' in JS file?
2) How to use "await" or "'FindAllAsync'" in this line? etc.
var cert = (await CertificateStores.FindAllAsync(certQuery)).FirstOrDefault(c=>c.Issuer.StartsWith("xxxx",StringComparison.CurrentCultureIgnoreCase));
WinJS.xhr wraps XMLHttpRequest( https://msdn.microsoft.com/en-us/library/windows/apps/br229787.aspx ) with a Promise-like interface (a WinJS Promise, not an ES6 Promise, but the concept is similar).
XMLHttpRequest has the withCredentials property which allows you to specify whether client-side credentials, including client-side certificates, should be sent or not - but there is no API that would allow you to specify which specific client-side certificate should be used.
Fortunately WinJS exposes the Windows.Web.Http.HttpClient type which gives you more control over client authentication, including client-side certificates - but your UWP application must have "Enterprise capability" to use the user's My certificate store - otherwise non-Enterprise UWP applications only have certificates in their Application Certificate Store:
https://blogs.windows.com/buildingapps/2015/11/23/demystifying-httpclient-apis-in-the-universal-windows-platform/#Dr3C9IMHv5pTPOrB.97
You must first add it to the app’s certificate store by following these instructions. Apps with enterprise capability can also use existing client certificates in the user’s ‘My’ store.
I am trying to stream data from a background server application to a client-side web-page using gevent-websocket.
When using localhost or leaving ('',8999) I am able to connect to the web-socket, but when trying to access from off the server I cannot seem to connect with the error 'Firefox can't establish a connection to the server at ws://SERVER-IP:8999/.'
I have tried other browsers with the same issue (well I tried chrome as well)
def app(environ, start_response):
ws = environ['wsgi.websocket']
stream_listener.add_socket(ws)
while not ws.closed:
gevent.sleep(0.1)
server = pywsgi.WSGIServer(
('0.0.0.0', 8999), app, handler_class=WebSocketHandler)
server.serve_forever()
As I said I have tried leaving it blank - putting in '0.0.0.0' in hopes that would bind it to all interfaces, but still no luck.
Here is the client side script that works from localhost - but trying to put in the SERVER-IP:8999 fails.
var ws = new WebSocket("ws://SERVER-IP:8999/");
ws.onopen = function() {
ws.send("Hello, world")
}, ws.onmessage = function(a) {
var b = JSON.parse(a.data);
//do something with b
};