Entwickler-Ecke

Programmiersprachen (Client) - WebSockets Packetverlust


Bergmann89 - Di 29.04.14 11:21
Titel: WebSockets Packetverlust
Hey Leute,

ich arbeite zur Zeit an einer Webseite die über WebSockets Daten mit dem Server austauscht. Das läuft so ab, das die Seite mehere Request (auf einmal) an den Server sendet und der diese dann alle nacheinander (nicht parallel) beantwortet. Nun habe ich das Problem, das ab und zu Packete verloren gehen (zumindest bekomm ich für das Packet kein WebSocket.onmessage Event), was ja bei TCP eigentlich nicht der Fall sein kann. Zum Test habe ich mir eine kleine Test-Seite gebaut, die den Fehlerfall nachstellt:

JavaScript-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
this.packageSize            = 4096;
this.timerHandle            = 0;
this.receivedPackageSize    = 0
this.inbound                = [];
this.sendDataCnt            = 0;
this.parallelRequests       = 2;

/* Request:  uint32 (number of requested bytes ); */
/* Response: uint32 (number of send bytes); uint8[] data; */

var webSocket = new WebSocket('ws://10.1.0.92:6325', ['istest']);
webSocket.binaryType = 'arraybuffer';

function sendDataRequest()
{
    var buf  = new ArrayBuffer(4);
    var view = new DataView(buf, 0);
    view.setUint32(0this.packageSize, true);
    for (var i = 0; i < this.parallelRequests; i++)
        webSocket.send(buf);
    $('#sendDataCnt')[0].innerHTML = this.sendDataCnt++;
}

webSocket.onopen = function()
{
    $('#log')[0].innerHTML += 'connected<br/>';
    this.timerHandle = setInterval(sendDataRequest, 100);
}.bind(this);

webSocket.onmessage = function(event)
{
    this.inbound.push.apply(this.inbound, new Uint8Array(event.data));
    if (this.receivedPackageSize == 0 && this.inbound.length >= 4)
    {
        var u8Arr = new Uint8Array(new ArrayBuffer(4));
        u8Arr.set(this.inbound.slice(04));
        this.receivedPackageSize = new DataView(u8Arr.buffer).getUint32(0true);
        this.inbound = this.inbound.slice(4);
        if (this.receivedPackageSize != this.packageSize)
        {
            clearInterval(this.timerHandle);
            $('#header')[0].innerHTML = 'ERROR: receivedPackageSize = ' + this.receivedPackageSize;
        }
        else
            $('#header')[0].innerHTML = 'receivedPackageSize = ' + this.receivedPackageSize;
        $('#data')[0].innerHTML = 'waiting for data...';
    }
    else if (this.inbound.length >= this.receivedPackageSize)
    {
        var u8Arr = new Uint8Array(new ArrayBuffer(this.receivedPackageSize));
        u8Arr.set(this.inbound.slice(0this.receivedPackageSize));
        this.inbound = this.inbound.slice(this.receivedPackageSize);
        for (var i = 0; i < this.receivedPackageSize; i++)
        {
            if (u8Arr[i] != (i & 0xFF))
            {
                clearInterval(timerHandle);
                $('#data')[0].innerHTML = 'ERROR: invalid package data';
                break;
            }
        }
        $('#data')[0].innerHTML = 'data OK';
        this.receivedPackageSize = 0;
    }
}.bind(this);

webSocket.onerror = function(e)
{
    clearInterval(timerHandle);
    $('#log')[0].innerHTML += 'error<br/>';
    console.log(e);
}.bind(this);

webSocket.onclose = function()
{
    clearInterval(timerHandle);
    $('#log')[0].innerHTML += 'disconnected<br/>';
}.bind(this);

Ich denke das es daran liegt, das ich mehrere Request gleichezeitig absende und dann auf die Antworten warte. Umso mehr Requests ich auf eimal absende (siehe Zeile 19 und 20), umso schneller habe ich inkonsistente Daten. Hat das Problem schonmal jmd gehabt, oder weiß jmd wie ich das lösen kann? Eine Lösungsmöglichkeit währe es immer nur ein Request zu schicken und dann auf die Anwort zu warten. Da bei TCP-Verbindungen aber parallele Request möglich sein sollten würde ich die Lösung nur ungern (sozusagen als Notlösung) nutzen.

MfG & Thx Bergmann.


Narses - Di 29.04.14 19:38

Moin!

user profile iconBergmann89 hat folgendes geschrieben Zum zitierten Posting springen:
Nun habe ich das Problem, das ab und zu Packete verloren gehen (zumindest bekomm ich für das Packet kein WebSocket.onmessage Event), was ja bei TCP eigentlich nicht der Fall sein kann.
Warum solle das nicht möglich sein können? ;) Klar geht das, aber bei TCP gibt´s dann eine Fehlermeldung (im Gegensatz zu UDP). :idea:

Abgesehen davon sichert der TCP-Stream lediglich die Socket-to-Socket Strecke ab, es ist immer noch möglich (ohne entsprechende Fehlermeldung/Ereignis, je nach Implementation, du bist ja nicht direkt auf der SocketAPI) einen Paketverlust im Empfangspuffer zu erleiden - weil du z.B. nicht schnell genug die Daten abholst! :shock:

cu
Narses


Bergmann89 - Di 29.04.14 21:17

Hey,

OK, wenn man das so sieht hast du Recht. Allerdings würde ich von einer guten API erwarten, das sie mir bei einem Packetverlust auch ein entsprechendes Event wirft und das tut sie im meinem Fall nicht. Das mit den Daten abholen glaub ich weniger. Der WebSocket wirft ein entsprechendes Event in dem die eingetroffenen Daten als Parameter übergeben werden, also gibt es ein "per Hand abholen" sogesehen nicht. Das der Eingans-Puffer voll läuft glaub ich auch nicht, dafür habe ich zu wenig Daten (in dem Beispiel 2 x 4k aller 100ms).

MfG Bergmann.


Narses - Di 29.04.14 21:21

Moin!

Senk die Datenrate und dein Problem ist weg. Wetten? :zwinker:

cu
Narses