What is the difference between BrokenPipeError and ConnectionAbortedError? - javascript

I am playing with eventlet's websocket. When I connect to a websocket from my browser, and then close the websocket from my browser, a ConnectionAbortedError is raised on the server side, but eventlet's documentation states that a BrokenPipeError should be raised.
I read Python's documentation about BrokenPipeError and ConnectionAbortedError but I don't understand the difference.
Here is the javascript code :
var socket = new WebSocket('ws://...');
socket.onmessage = function(m){console.log(m.data);};
socket.close();

Related

Prevent theoretical loss of the first received message in WebSocket

Code on server-side sends a message immediately after connection is opened (it sends initial configuration/greetings to a client).
And the following code is on client-side:
var sock = new WebSocket(url);
sock.addEventListener('error', processError);
sock.addEventListener('close', finish);
sock.addEventListener('message', processMessage);
I worry about losing this first configuration/greetings-related message from server. Theoretically nothing prevents it from being received before message event handler is set.
On the other hand, practically it never occurred to me. And AFAIK JavaScript WebSocket API doesn't have countermeasures against this theoretical issue: the WebSocket constructor neither allows message event handler to be set, nor allows WebSocket to be created in suspended state.
So:
Either I am missing something, and loss of message with the above code is impossible even theoretically.
Or it is bug in JavaScript WebSocket API design.
Or everyone is just happy because message loss is practically impossible.
Or such behavior (sending message from server on connection) is somewhy considered bad practice, so no one bothers about possibility to implement it theoretically correct.
?
P.S.: Do such simple-but-theoretical questions better fit Stack Overflow or Programmers#Stack Exchange?
Don't worry.
Your code is running within a single threaded event loop.
This line: var sock = new WebSocket(url); doesn't initiate a websocket connection at all. The spec says that it must perform the actual connection only after returning the web socket, in parallel with the thread handling the event loop your code is running on:
Return a new WebSocket object, but continue these steps [in parallel][2].
That alone wouldn't be sufficient, but all subsequent WebSocket events for that socket are scheduled inside the same single-threaded event loop that is running your code. Here's what the spec says about receiving a message:
When a WebSocket message has been received with type type and data data, the user agent must queue a task to follow these steps
That task is queued on the same event loop. That means that the task to process the message cannot be run until the task where you created your WebSocket has run to completion. So your code will finish running before the event loop will process any connection related messages.
Even if you're running your code in a browser that uses many threads, the specific code will run on a single threaded event loop and each event loop will be independent.
Different event loops can and do communicate by pushing tasks into each other's task-queues. But these tasks will be executed within the single-threaded event-loop that received the task, keeping your code thread-safe.
The task "handle this event" will be handled by the single threaded event loop finding the appropriate event handler and calling its callback... but this will only happen once the task is already being handled.
To be clearer:
I'm not claiming that each event-loop actually handles the IO - but the IO scheduler will send your code events and these events will run sequentially within a single thread (sort of, they do have priority management that uses different "task queues").
EDIT: client code concerns
It should be noted that the Websocket API wasn't designed for the DOM's function addEventListener.
Instead, the Websocket API follows the HTML4 paradigm, where event callbacks are object properties (rather than the EventListener collection). i.e.:
// altered DOM API:
sock.addEventListener('message', processMessage);
// original WebSocket API:
sock.onmessage = processMessage;
Both APIs work correctly on all the browsers I tested (including safe delivery of first message). The difference in approaches is probably handled by the HTML4 compatibility layer.
However the specification regarding event scheduling is different, so the use of addEventListener should probably be avoided.
EDIT 2 : Testing the Theory
Regarding Bronze Man's answer concerning failed message responses...
I couldn't reproduce the claimed issue, even though I wrote a test using a small Ruby application and a small Javascript Client.
The Ruby application starts up a Websocket echo server with a welcome message (I'm using plezi.io).
The Javascript client contains a busy-wait loop that causes the Javascript thread to hang (block) for the specified amount of time (2 seconds in my tests).
The onmessage callback is set only after the block is released (after 2 seconds) - so the welcome message from the server will arrive at the browser before the callback is defined.
This allows us to test if the welcome message is lost on any specific browser (which would be a bug in the browser).
The test is reliable since the server is a known quantity and will send the message to the socket as soon as the upgrade is complete (I wrote the Iodine server backend in C as well as the plezi.io framework and I chose them because of my deep knowledge of their internal behavior).
The Ruby application:
# run from terminal using `irb`, after `gem install plezi`
require 'plezi'
class WebsocketEcho
def index
"Use Websockets"
end
def on_message data
# simple echo
write data
end
def on_open
# write a welcome message
# will ths message be lost?
write "Welcome to the WebSocket echo server."
puts "New Websocket connection opened, welcome message was sent."
end
end
# adds mixins to the class and creates route
Plezi.route("/", WebsocketEcho)
# running the server from the terminal
Iodine.threads = 1
Iodine::Rack.app = Plezi.app
Iodine.start
The Javascript Client:
function Client(milli) {
this.ws = new WebSocket("ws" + window.document.location.href.slice(4, -1));
this.ws.client = this;
this.onopen = function (e) { console.log("Websocket opened", e); }
this.ws.onopen = function (e) { e.target.client.onopen(e); }
this.onclose = function (e) { console.log("Websocket closed", e); /* reconnect? */ }
this.ws.onclose = function (e) { e.target.client.onclose(e); }
if(milli) { // busy wait, blocking the thread.
var start = new Date();
var now = null;
do {
now = new Date();
} while(now - start < milli);
}
this.onmessage = function (e) { console.log(e.data); }
// // DOM API alternative for testing:
// this.ws.addEventListener('message', function (e) { e.target.client.onmessage(e); });
// // WebSocket API for testing:
this.ws.onmessage = function (e) { e.target.client.onmessage(e); }
}
// a 2 second window
cl = new Client(2000);
Results on my machine (MacOS):
Safari 11.01 initiates the Websocket connection only after the new client was creation is complete (after the thread is done processing the code, as indicated by the Ruby application's delayed output). The message obviously arrived once the connection was made.
Chrome 62.0 initiates the Websocket connection immediately. The message arrives once the 2 second window ends. Message wasn't lost even though it arrived before the onmessage handler was set.
FireFox 56.0 behaves the same as Chrome, initiating the Websocket connection immediately. The message arrives once the 2 second window ends. Message wasn't lost.
If someone could test on Windows and Linux, that would be great... but I don't think the browsers will have implementation issues with the event scheduling. I believe the specifications can be trusted.
Your theory is true and real.
I ACTUALLY got into this situation on chrome 62 on ubuntu 1404 when my chrome extension background page open a websocket connection to 127.0.0.1 server. My server send serval messages first to the app. And the first serval messages may lost and may not lost. But this bug do not happen on my mac chrome 62. I think this is what data race looks like.It may never happen, but it may happen in theory. So we need to prevent it happen.
Here is my client code looks like:
var ws = new WebSocket(url);
var lastConnectTime = new Date();
ws.onerror = processError;
ws.onclose = finish;
ws.onmessage = processMessage;
Solution
The solution should be the server must wait client first message(even if it do not have any information) then send message to client.
Here is my solution in client js in code:
var ws = new WebSocket(url);
var lastConnectTime = new Date();
ws.onerror = processError;
ws.onclose = finish;
ws.onmessage = processMessage;
ws.onopen = function(){
ws.send("{}");
};
Here is my solution in golang server:
func (s *GoServer)ServeHTTP(w http.ResponseWriter, r *http.Request){
fmt.Println("WebsocketServeHttp recv connect",r.RemoteAddr)
conn,err:=websocket.Upgrade(w,r,nil,10240,10240)
if err!=nil{
panic(err)
}
_,_,err=conn.ReadMessage()
if err!=nil{
panic(err)
}
//... (you can send message to the client now)
}
Confirming that the problem does exist (as a rare but real situation) on Chrome 62 and 63 on Ubuntu: occasional loss of first message from server. I confirmed with tcpdump that there is indeed a handshake packet and then the packet for the first message. In the client, the first message even shows up in the Networking tab as a first frame on the websocket. Then onopen callback is called, but onmessage is NOT.
I agree that it doesn't seem possible, and looking at WebKit's implementation of WebSocket, it doesn't seem possible, and I've never seen it on Chrome Mac or in Firefox, so my only guess is that Chrome on Ubuntu introduced a race condition with some optimization.
You can definitely lose messages! The accepted answer is misleading. All that has to happen is that you do an operation that relinquishes the thread of control between the open event and configuring a message listener.
Is that likely to happen? Who knows, it depends on your application. Here's the situation that led me to waste too much time debugging this (the api sucks!) using the ws library on the server:
On the server:
async handleOpen(socket, request) {
const session = await getSession(cookie.parse(request.headers.cookie).id);
const user = new User(session.user.id, socket);
user.socket.addEventListener('message', this.handleMessage.bind(this, user));
}
See that await? That relinquishes control and allows events to be lost. For what it's worth, the session was stored in memcached so was not immediately available.

Javascript Sockets (failed: Error during WebSocket handshake: net::ERR_CONNECTION_RESET)

I am trying to create a simple program to send a message to a socket in plain text. The sender is a webpage in javascript using websocket and the server is a C program. I don't have any control over the C code but I have been assured by the codes owners that I can use simple javascript to send the message. My code is as follows:
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript">
//initialize the websocket ws
var ws;
//Open the socket connection
function openSock() {
//test for Websocket compatibility in the browser
if ("WebSocket" in window) {
// log socket attempt
console.log("Attempting to open socket!");
//open web socket ws
ws = new WebSocket("ws://192.168.6.222:11000/echo");
} else { // else the browser doesn't support WebSocket
//Websocket is not supported
alert("APS NOT supported by your Browser!");
}
}
//send the command to socket ws
function sendCommand() {
console.log("Attempting to Send Message");
ws.send("your message here");
}
//close the socket ws
function closeSock() {
console.log("Closing Socket");
// close socket ws
ws.close();
}
</script>
</head>
<body>
<div id="sse">
<input type=submit value="open">
<input type=submit value="send">
<input type=submit value="close">
</div>
</body>
</html>
When I click the connect button I get this error:
WebSocket connection to 'ws://192.168.6.222:11000/echo' failed: Error during WebSocket handshake: net::ERR_CONNECTION_RESET
I have checked the firewall and the port seems to be open. After spending a fair amount of time troubleshooting the server (making sure it is running and on the network, etc.) I am wondering if I did something wrong with this client side code.
From my limited knowledge and the reading I have done this looks correct but any help is welcome.
This is probably super late but I just ran into a similar problem while using Django channels. I fixed it by adding a slash (/) at the end of the URL.
ws = new WebSocket("ws://192.168.6.222:11000/echo/");
How does the server side of the connection look like?
Maybe you are using a faulty WebSocket Lib which does not provide a valid handshake.
Because when testing the client against ws://echo.websocket.org everything seems to work perfectly fine. This strongly suggests that the websocket client is not source of the problem.
Make sure that your queue is running properly, in my case that was the issue

Client unable to connect to server websocket using gevent-websocket

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
};

Why can not I open a UDP connection on the client side (in browser)?

I know that there WebSockets. I looked at it from itself is an example of language dart.
void initWebSocket([int retrySeconds = 2]) {
var reconnectScheduled = false;
outputMsg("Connecting to websocket");
ws = new WebSocket('ws://echo.websocket.org');
void scheduleReconnect() {
if (!reconnectScheduled) {
new Timer(new Duration(milliseconds: 1000 * retrySeconds), () => initWebSocket(retrySeconds * 2));
}
reconnectScheduled = true;
}
ws.onOpen.listen((e) {
outputMsg('Connected');
ws.send('Hello from Dart!');
});...
That is nothing but the creation of new connections and work with it already.
That is a separate thread (in fact, in which runs javaScript) connection is established and so on.
Why then dart and JavaScript I can not in the same thread to open a simple UDP connection and work with him?
P.s.UDP is more preferred for online-browser-realtime-games.
The browsers don't support it due to security constraints.
You should take a look at WebRTC
see also
How to send a UDP Packet with Web RTC - Javascript?
Can I use WebRTC to open a UDP connection?

Poor network performance with Websockets running on apple device

I am working on an HTML/Javascript running on mobile devices that is communicating with a Qt/C++ application running on a PC. Both the mobile device and the PC are on a local network. The communication between the HTML page (client) and the C++ app (server) is done using Websockets.
The HTML page is a remote control for the C++ application, so it is needed to have a low latency connection between the mobile device and the PC.
When using any non-Apple device as a client, data is sent to a rate between 60 to 120 frames/sec, which is totally acceptable. When using an Apple device, this rate falls to 3-4 frames/sec.
I also checked ping times (Websocket implementation, not a ping command from command line). They are acceptable (1-5 ms) for Apple devices as long as the device is not transmitting data. Whenever it transmits data, this ping time raises to 200ms.
Looking from the Javascript side, the Apple devices always send data at a consistent rate of 60 frames/sec, as any other devices do. However, on the server side, only 3 to 4 of these 60 frames are received when the client is an Apple device.
Does anyone have any idea on what can be happening?
Here is my Javascript code :
<script language="javascript" type="text/javascript">
var wsUri = document.URL.replace("http", "ws");
var output;
var websocket;
function init()
{
output = document.getElementById("output");
wsConnect();
}
function wsConnect()
{
console.log("Trying connection to " + wsUri);
try
{
output = document.getElementById("output");
websocket = new WebSocket(wsUri);
websocket.onopen = function(evt)
{
onOpen(evt)
};
websocket.onclose = function(evt)
{
onClose(evt)
};
websocket.onmessage = function(evt)
{
onMessage(evt)
};
websocket.onerror = function(evt)
{
onError(evt)
};
}
catch (e)
{
console.log("Exception " + e.toString());
}
}
function onOpen(evt)
{
alert("Connected to " + wsUri);
}
function onClose(evt)
{
alert("Disconnected");
}
function onMessage(evt)
{
alert('Received message : ' + evt.data);
}
function onError(evt)
{
alert("Error : " + evt.toString());
}
function doSend(message)
{
websocket.send(message);
}
window.addEventListener("load", init, false);
</script>
Data is sent from Javascript side using dosend() function.
Few ideas and suggestions.
Check if the client's WebSocket protocol is supported by the server. This question and answer discuss a case where different protocol versions were an issue.
The WebSocket standard permits implementations to arbitrarily delay transmissions and perform fragmentation. Additionally, control frames, such as Ping, do not support fragmentation, but are permitted to be interjected. These permitted behavioral difference may be contributing to the difference in times.
Check if the bufferedAmount attribute on the WebSocket to determine if the WebSocket is buffering the data. If the bufferedAmount attribute is often zero, then data has been passed to the OS, which may be buffering it based on OS or socket configurations, such as Nagle.
This question and answer mentions resolving delays by having the server send acknowledgements for each message.
To get a deeper view into the interactions, it may be useful to perform a packet trace. This technical Q&A in the Mac Developer Library may provide some resources as to how to accomplish this.
The best way to get some more insight is to use the AutobahnTestsuite. You can test both clients and servers with that suite and find out where problems are situated.
I have created QWebSockets, a Qt based websockets implementation, and used that on several occasions to create servers. Performance from Apple devices is excellent.
However, there seems to be a severe problem with Safari when it comes to large messages (see https://github.com/KurtPattyn/QWebSockets/wiki/Performance-Tests). Maybe that is the problem.

Categories