When sending the same data in both Fetch
and WebSocket
, there is a noticeable speed difference:
- HTTP takes
29
seconds to transfer around200 MB
. - WebSocket takes
6
seconds to transfer around200 MB
.
An Interesting Observation:
Why does WebSocket
outperform HTTP
? Is it due to encoding, technology, or something else?
Investigating Fetch:
async function postData(url = '', data) {
const response = await fetch(url, {
method: 'POST',
mode: 'no-cors',
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/octet-stream'
},
redirect: 'follow',
referrerPolicy: 'no-referrer',
body: data
});
return response; //.arrayBuffer();
}
postData('http://localhost:3800/buffer', arrU8)
.then(data => {
console.log(data);
});
arrU8
is an Uint8Array
with a length of 185578200
Delving into WebSocket:
function connect() {
return new Promise(function (resolve, reject) {
var ws = new WebSocket('ws://127.0.0.1:8081/echo');
ws.onopen = function () {
resolve(ws);
};
ws.onerror = function (err) {
reject(err);
};
ws.onclose = function (evt) {
console.log("CLOSE SOCKET", new Date().toLocaleString());
};
ws.onmessage = function (evt) {
console.log("RESPONSE SOCKET: " + "RECEIVED" /* evt.data */, new Date().toLocaleString());
};
});
}
connect().then(function (ws) {
// onopen
ws.binaryType = 'arraybuffer';
ws.send(arrU8);
ws.close();
}).catch(function (err) {
// onerror
console.log("ERROR: " + evt.data, new Date().toLocaleString());
});
The Server Side Utilizes GO Language:
Looking at HTTP:
func process(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/buffer" {
http.Error(w, "404 not found.", http.StatusNotFound)
return
}
switch r.Method {
case "GET":
fmt.Fprintf(w, "GET request is received: %s \n", r.URL)
case "POST":
body, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
log.Println("Data length received = ", len(body))
fmt.Fprintf(w, "Data length = %v \n", len(body))
default:
fmt.Fprintf(w, "Sorry, only GET and POST methods are supported.")
}
}
Unveiling WebSocket:
package main
import (
"flag"
"log"
"net/http"
"text/template"
"github.com/gorilla/websocket"
)
var addr = flag.String("addr", "localhost:8081", "http service address")
var upgrader = websocket.Upgrader{} // use default options
func main() {
log.Println("Launching WebSocket server...", *addr)
flag.Parse()
log.SetFlags(log.LstdFlags | log.Lmicroseconds)
http.HandleFunc("/echo", echo)
http.HandleFunc("/", home)
log.Fatal(http.ListenAndServe(*addr, nil))
}
func echo(w http.ResponseWriter, r *http.Request) {
// To fix 403 error temporarily. It's unsafe:
upgrader.CheckOrigin = func(r *http.Request) bool { return true }
c, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Print("upgrade:", err)
return
}
defer c.Close()
for {
mt, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
break
}
log.Println("recv: message type:", mt)
log.Printf("recv: bytes count: %v", len(message))
// // // Disable echo and log
// log.Printf("recv: %s", message)
// err = c.WriteMessage(mt, message)
// if err != nil {
// log.Println("write:", err)
// break
// }
}
}
func home(w http.ResponseWriter, r *http.Request) {
homeTemplate.Execute(w, "ws://"+r.Host+"/echo")
}