I'm working on a websocket application. I have a server that is written in C#. I have tested it using another C# application for sending and receiving data. The problem occurs when I use a JavaScript on the chrome developer tool (console) and use Websockets to connect to my server.
I receive the header string from the websocket script, with two keys and the last 8 characters for hashing.
I used the header string keys to generate a hash code and crate a header to send back to chrome(j script on the developer tool).
Issues:-
the onopen event is never triggered and the websocket does not receive the header(I assume). I use the onerror to capture any errors. Which never occur.
The readystate on the websocket is 0 or 2(always).
But when I send a disconnect response from the server, the websocket triggers the onclose method. (So I assume that he was open but not ready to communicate)
Any suggestions??????? Here's the JavaScript if it helps.
websocket = new WebSocket('ws://My server IP here:8080');
try {
websocket.onopen = function(evt) {
open(evt)
//websocket.send("Message to send");
alert("Message is sent...");
}
}
catch(err) {
debug(err,'error')
}
websocket.onerror = function(evt) {
error(evt)
}
websocket.onclose = function(evt) {
close(evt)
}
websocket.onmessage = function(evt) {
message(evt)
}
function open(evt) {
alert("CONNECTED");
doSend("WebSocket rocks");
}
function error(evt) {
alert (evt.data)
}
function close(evt) {
alert("DISCONNECTED");
}
function message(evt) {
alert(evt.data);
}
function doSend(message) {
alert(message);
websocket.send(message);
}
And the header I sent back
HTTP/1.1 101 WebSocket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Origin: chrome://newtab
Sec-WebSocket-Location: ws://My server IP:8080
??i???m?!??9?
Thanks everyone.
It looks like you're trying to respond to the handshake request without the appropriate challenge response. Like Robin mentioned, the handshake is now more complex and involves a challenge for newer versions of the WebSocket protocol. This is a good article that explains the version 76 handshake in more detail.
Here's a code sample that detects the WebSocket protocol version and replies with the appropriate response. (It's in Java, so YMMV, but it should point you in the right direction.)
// Create the WebSocket handshake response.
HttpResponse res = new DefaultHttpResponse(HTTP_1_1,
new HttpResponseStatus(101, "Web Socket Protocol Handshake"));
res.addHeader(Names.UPGRADE, WEBSOCKET);
res.addHeader(CONNECTION, Values.UPGRADE);
// Fill in the headers and contents depending on handshake method.
// New handshake specification has a challenge.
if (req.containsHeader(SEC_WEBSOCKET_KEY1)
&& req.containsHeader(SEC_WEBSOCKET_KEY2)) {
// New handshake method with challenge
res.addHeader(SEC_WEBSOCKET_ORIGIN, req.getHeader(ORIGIN));
res.addHeader(SEC_WEBSOCKET_LOCATION, getWebSocketLocation(req));
String protocol = req.getHeader(SEC_WEBSOCKET_PROTOCOL);
if (protocol != null) {
res.addHeader(SEC_WEBSOCKET_PROTOCOL, protocol);
}
// Calculate the answer of the challenge.
String key1 = req.getHeader(SEC_WEBSOCKET_KEY1);
String key2 = req.getHeader(SEC_WEBSOCKET_KEY2);
int a = (int) (Long.parseLong(key1.replaceAll("[^0-9]", "")) / key1
.replaceAll("[^ ]", "").length());
int b = (int) (Long.parseLong(key2.replaceAll("[^0-9]", "")) / key2
.replaceAll("[^ ]", "").length());
long c = req.getContent().readLong();
ChannelBuffer input = ChannelBuffers.buffer(16);
input.writeInt(a);
input.writeInt(b);
input.writeLong(c);
ChannelBuffer output = ChannelBuffers
.wrappedBuffer(MessageDigest.getInstance("MD5").digest(
input.array()));
res.setContent(output);
} else {
// Old handshake method with no challenge:
res.addHeader(WEBSOCKET_ORIGIN, req.getHeader(ORIGIN));
res.addHeader(WEBSOCKET_LOCATION, getWebSocketLocation(req));
String protocol = req.getHeader(WEBSOCKET_PROTOCOL);
if (protocol != null) {
res.addHeader(WEBSOCKET_PROTOCOL, protocol);
}
}
// Send the response...
Are you implementing the correct Websockets Protocol version? Chrome has moved to version 76, which means the handshake is more complex than it was. If your Javascript client is failing to connect properly this is possibly the cause.
Related
I'm trying to use a C# Socket.IO implementation for IPC with my Node server.
I looked up a few examples online and the Socket.IO seems to establish, however it's not triggering events.
I was using this article for the basic example that had been confirmed working but haven't had much luck. (websocket-sharp how to work with socketio server and send "emit" request)
I've tried to debug a working Node - Node / Client - Server implementation to see where this might be going wrong but I honestly can't tell. Also the post request I found on this answer here: Communicating with a socket.io server via c# so I first thought it was required to use a post request and in a Wireshark capture I can see a get request, though I think that may just be part of the io engine..
I can see that data is being received by the server but when I do a debug on the Node server I get the following:
listening on port: 4444
express:router use '/' query +107ms
express:router:layer new '/' +0ms
express:router use '/' expressInit +2ms
express:router:layer new '/' +0ms
express:router use '/' jsonParser +0ms
express:router:layer new '/' +1ms
express:router use '/' urlencodedParser +1ms
express:router:layer new '/' +0ms
express:router:route new '/' +1ms
express:router:layer new '/' +0ms
express:router:route post '/' +0ms
express:router:layer new '/' +0ms
engine handshaking client "peXO2SOcvKhmEotXAAAA" +0ms
engine:socket sending packet "open" ({"sid":"peXO2SOcvKhmEotXAAAA","upgrades":[],"pingInterval":25000,"pingTimeout":5000}) +0ms
engine:socket flushing buffer to transport +1ms
engine:ws writing "0{"sid":"peXO2SOcvKhmEotXAAAA","upgrades":[],"pingInterval":25000,"pingTimeout":5000}" +0ms
engine:transport setting request +0ms
socket.io:server incoming connection with id peXO2SOcvKhmEotXAAAA +13s
engine:ws received "42["connection"]" +45ms
engine:socket packet +48ms
socket.io-parser decoded 2["connection"] as {"type":2,"nsp":"/","data":["connection"]} +0ms
socket.io:client no socket for namespace / +0ms
engine:ws received "42["init","Hello"]" +129ms
engine:socket packet +127ms
socket.io-parser decoded 2["init","Hello"] as {"type":2,"nsp":"/","data":["init","Hello"]} +126ms
socket.io:client no socket for namespace / +125ms
engine:socket writing ping packet - expecting pong within 5000ms +25s
engine:socket sending packet "ping" (undefined) +1ms
engine:socket flushing buffer to transport +0ms
engine:ws writing "2" +25s
engine:ws received "42["init","Hello"]" +5ms
engine:socket packet +5ms
socket.io-parser decoded 2["init","Hello"] as {"type":2,"nsp":"/","data":["init","Hello"]} +25s
socket.io:client no socket for namespace / +25s
This is my server code:
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server),
util = require('util'),
bodyParser = require('body-parser');
var port = process.env.port || 4444;
server.listen(port);
console.log("listening on port: " + port);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.post("/", function (req, res) {
// look for parameters from form input
var data = {
ID: req.body.ID,
};
console.log("sending request to interperet new data");
console.log(req.body);
// send the message to console app
io.emit("test",data);
});
io.on('connection', ( socket ) => {
console.log("New user joined");
socket.on('connect', () => {
console.log("New user joined");
setTimeout(() => {
console.log("Emitting test...");
io.emit("test", data);
res.send("OK");
}, 1500);
});
});
And my C# code (if that helps):
var ws = new WebSocket ("ws://<IP>:4444/socket.io/?EIO=2&transport=websocket");
ws.OnOpen += (sender, e) => {
ws.Send("42[\"connection\", {\"dummy\":\"data\"}]");
};
ws.Connect ();
Any help getting my head around this would be much appreciated
For anyone having this issue... I have managed to fix this after I did some reading and found What do these numbers mean in socket.io payload?
To get this working I had to change my on open message to
ws.Send("40[<data>]")
As the client connected, this was first hitting the io.on('connection') event on the server side which would then send back to the client who's OnMessage was being fired and then when sending back with ws.Send("42[]").
There's probably some reason why but this is literally all I changed and it now seems to be something I can work with.
I built a Websocket Server in Java with Spring Boot
My server configuration looks like:
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic", "/queue");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry
.addEndpoint("/my-websocket")
.setAllowedOrigins("*")
.withSockJS();
}
I've created a client in Javascript which works, and the connection looks like:
function connect() {
var myUsername = document.getElementById('from').value;
var host = 'http://localhost:8080/my-websocket';
var socket = new SockJS(host);
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
stompClient.send('/app/status', {}, JSON.stringify(createUserStatus('AVAILABLE')));
stompClient.subscribe('/topic/status', function (message) {
receiveStatus(JSON.parse(message.body));
});
stompClient.subscribe('/queue/private.message.' + myUsername, function (message) {
displayMessage(JSON.parse(message.body));
});
});
}
Now I want to create a client in .NET, but every Stomp client library I've found, doesn't allow http to be the URI, and my server only accepts http connections. My server fails to parse ws and tcp connections, and I can't find a client out there that uses http.
In my .NET client, when I try to connect to string brokerUri = "tcp://localhost:8080/my-websocket"
My server throws this exception:
client-id:ID:DESKTOP-AA29FJ6-52716-637205011942817986-0:0
host:localhost
accept-version:1.0,1.1
heart-beat:10000,30000
]
2020-03-22 19:13:14.414 DEBUG 25036 --- [nio-8080-exec-2] o.apache.coyote.http11.Http11Processor : Error parsing HTTP request header
java.lang.IllegalArgumentException: Invalid character found in method name. HTTP method names must be tokens
How can I create a Websocket connection in .NET that can subscribe to different topics and queues, and send messages over http?
Alternatively, how could I make my server handle ws or tcp connections?
Thank you!
Hey I'm trying to create a messaging app using SocketIO. I have a server written in flask and a client written in C#. I'm using SocketIoClientDotNetfor the client (https://github.com/Quobject/SocketIoClientDotNet).
This is my code:
Flask: routes.py
from flask import Flask
from flask.ext.socketio import SocketIO, emit
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)
#app.route('/')
def home():
return "hello"
#socketio.on('connect')
def connect():
print("CONNECTED")
#socketio.on("message")
def test():
print("TEST WORKS")
if __name__ == '__main__':
socketio.run(app)
C# :
public static class EnvConnections {
public static IO.Options CreateOptions() {
var options = new IO.Options();
options.Port = 5000;
options.Hostname = "127.0.0.1";
options.ForceNew = true;
return options;
}
public static void Connect() {
Uri uri = new Uri("http://127.0.0.1:5000");
var socket = IO.Socket(uri, CreateOptions()); //also tried to create the socket only with url IO.Socket("http://127.0.0.1:5000")
socket.On(Socket.EVENT_CONNECT, () => {
Console.Write("EVENT_CONNECT");
socket.Disconnect();
});
socket.Connect(); //tried to remove this
Console.ReadLine();
}
On both platforms nothing is printed. It looks like a connection is created between them (on flask this line is printed infinitely once the connection is establish : 127.0.0.1 - - [20/Jan/2016 11:23:43] "GET /socket.io/?EIO=3&transport=polling&t=635888858234059292-4049&b64=1 HTTP/1.1" 200 -)
What am I doing wrong?
Edit: after I installed gevent I started receiving connect events. The problem is that its stuck on it and no other function is called. Looking at the flask console it looks like it uses pulling instead of webSocket (some kind of fullback mechanism) so I tried to change the c# socket option:
IO.Options options = new IO.Options();
//options.Transports = ImmutableList.Create<string>(Polling.NAME);
options.Upgrade = true;
var socket = IO.Socket("http://127.0.0.1:5000", options);
But it keeps printing transport=polling
Edit2:
fb0f4c189334468dba90255880b528a4: Sending packet MESSAGE with 0
127.0.0.1 - - [20/Jan/2016 17:49:13] "GET /socket.io/?EIO=3&transport=polling&t=635889089536079075-2035&b64=1 HTTP/1.1" 200 355 0.002000
5cea6ce4dd8b47d79e79dd96747c26e4: Sending packet OPEN with {'pingTimeout': 60000, 'sid': '5cea6ce4dd8b47d79e79dd96747c26e4', 'upgrades': ['websocket'], 'pingInterval': 25000}
5cea6ce4dd8b47d79e79dd96747c26e4: Sending packet MESSAGE with 0
127.0.0.1 - - [20/Jan/2016 17:49:13] "GET /socket.io/?EIO=3&transport=polling&t=635889089536109077-2036&b64=1 HTTP/1.1" 200 355 0.003000
f768281808204af995421b4dbb2cda1c: Sending packet OPEN with {'pingTimeout': 60000, 'sid': 'f768281808204af995421b4dbb2cda1c', 'upgrades': ['websocket'], 'pingInterval': 25000}
CONNECTED
CONNECTED
f768281808204af995421b4dbb2cda1c: Sending packet MESSAGE with 0
127.0.0.1 - - [20/Jan/2016 17:49:13] "GET /socket.io/?EIO=3&transport=polling&t=635889089536149079-2037&b64=1 HTTP/1.1" 200 355 0.002000
e4eb16fcd12f41898ba58a309014b85c: Sending packet OPEN with {'pingTimeout': 60000, 'sid': 'e4eb16fcd12f41898ba58a309014b85c', 'upgrades': ['websocket'], 'pingInterval': 25000}
e4eb16fcd12f41898ba58a309014b85c: Sending packet MESSAGE with 0
127.0.0.1 - - [20/Jan/2016 17:49:13] "GET /socket.io/?EIO=3&transport=polling&t=635889089536179081-2038&b64=1 HTTP/1.1" 200 355 0.002000
70f45826d89b42bba3842e41b8ae8b08: Sending packet OPEN with {'pingTimeout': 60000, 'sid': '70f45826d89b42bba3842e41b8ae8b08', 'upgrades': ['websocket'], 'pingInterval': 25000}
70f45826d89b42bba3842e41b8ae8b08: Sending packet MESSAGE with 0
127.0.0.1 - - [20/Jan/2016 17:49:13] "GET /socket.io/?EIO=3&transport=polling&t=635889089536219083-2039&b64=1 HTTP/1.1" 200 355 0.002000
CONNECTED
CONNECTED
To turn my comment into a proper answer:
The problem appears to be that the upgrading mechanism from long-polling to WebSockets does not work between these particular socket.io implementations. By configuring the client to directly use WebSockets, I got it to work. Here an example:
var socket = IO.Socket("http://127.0.0.1:5000/data", new IO.Options
{
// The protocol upgrading does not properly work between Flask-SocketIO and SocketIOClientDotNet
Transports = ImmutableList<string>.Empty.Add(WebSocket.NAME)
});
The problem is related to the encoding sent back by the server. Flask Socket IO is not returning text/plain which is what is meant to return when a base64 parameter is included in the request (b64=1). Instead it returns an octet-stream.
The C# library adds b64=1 to the request automatically and changing the ForceBase64 property doesn't change that unfortunately.
Currently the only way I have found to fix this is to adjust the source for EngineIoClientDotNet, editing Polling.cs and removing query.Add("b64","1").
This may have untoward effects if the library doesn't support binary but so far it is now connecting successfully.
I'm making a api service which connects to a SSL TCP server to retrieve data. I first made this api in C# and it works. Later I ported it to node.js to take the advantages of node.js. However I couldn't connect to the server.
Target :
Host : prodtw.lol.garenanow.com
Port : 2099
Code in C# which can connect to the server and works perfectly:
TcpClient client;
try
{
client = new TcpClient("prodtw.lol.garenanow.com", 2099);
Console.WriteLine("Connected to server.");
}
catch
{
Console.WriteLine("Error");
return;
}
SslStream sslStream = new SslStream(client.GetStream(), false, AcceptAllCertificates); //AcceptAllCertificate does nothing, just return true
var ar = sslStream.BeginAuthenticateAsClient("prodtw.lol.garenanow.com", null, null);
using (ar.AsyncWaitHandle)
{
if (ar.AsyncWaitHandle.WaitOne(-1))
sslStream.EndAuthenticateAsClient(ar);
}
// Connected, write something
byte[] handshakePacket = new byte[1537];
sslStream.Write(handshakePacket);
Code in node.js, which couldn't connect to the SSL TCP server :
var tls = require('tls');
console.log('Connecting');
var stream = tls.connect(2099, "prodtw.lol.garenanow.com", function() {
console.log('Successfully connected!'); //Never print this message.
});
After running the above node.js code, it never shows "Successfully connected". It only shows "Connecting" and stucks at tls.connect...
I was using Alchemy websockets for both my client and server but ran into a problem with corrupted/dropped messsages. So I'm trying out another server side implementation. I implemented the server using Fleck, and when I send messages using javascript, the server receives all the messages, solving my previous problem.
However, I need to be able to send messages to the websocket server from a C# client also. Since Fleck does not have a client side implementation in C#, I thought I'd stick with Alchemy. I left the client-side code unchanged so I thought it should just connect to the server as before, however, no messages are being received (though they are being sent according to the debugger).
Here is my server side implementation (Fleck):
private void OnStartWebSocketServer()
{
var server = new WebSocketServer("ws://localhost:11005");
server.Start(socket =>
{
socket.OnOpen = () => Console.WriteLine("Open!");
socket.OnClose = () => Console.WriteLine("Close!");
socket.OnMessage = message => OnReceive(message);
});
}
private static void OnReceive(String message)
{
UpdateUserLocation(message);
}
Here is my client side implementation (Alchemy):
class WSclient
{
WebSocketClient aClient;
public WSclient(String host, String port)
{
aClient = new WebSocketClient("ws://" + host + ":" + 11005 + "/chat")
{
OnReceive = OnReceive,
OnSend = OnSend,
OnConnect = OnConnected,
OnConnected = OnConnect,
OnDisconnect = OnDisconnect
};
aClient.Connect();
}
...
public void Send(String data)
{
aClient.Send(data);
}
I thought it might have something to do with the fact that the Alchemy client requires a channel at the end of the connection string '/chat'. However leaving it blank, or just the '/' gives an error.