WebSockets
lima-city → Forum → Die eigene Homepage → HTML, CSS & Javascript
aufwendigere sachen
blocken
byte
code
dank
fehler
frage
http
index
listen
machen
message
nachricht
server
string
system
tester
text
url
weben
-
Hallo zusammen
Ich habe mich in letzter Zeit etwas mit websockets beschäftigt. Mein Ziel ist es eigentlich einen kleinen Web-Chat zu machen.
Als Test hab ich mir einen kleinen J-Script erstellt
function connect() { var ws = new WebSocket("ws://localhost:100"); ws.onopen = function () { alert("Open!"); } ws.onmessage = function (evt) { alert("About to receive data"); var received_msg = evt.data; alert("Message received = "+received_msg); } ws.onclose = function () { alert("Connection is closed..."); } }
Auf VS hab ich mir dann einen "Server" gemacht
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; namespace test_server { class Program { private static byte[] _buffer = new byte[2048]; private static Socket _serverSocket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); static void Main(string[] args) { Console.Title = "Server"; SetupServer(); Console.ReadLine(); } private static void SetupServer() { Console.WriteLine("Setting up server..."); _serverSocket.Bind(new IPEndPoint(IPAddress.Any, 100)); _serverSocket.Listen(5); _serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), true); } private static void AcceptCallback(IAsyncResult AR) { Socket socket = _serverSocket.EndAccept(AR); Console.WriteLine("Client connected"); socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket); _serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), true); } private static void ReceiveCallback(IAsyncResult AR) { try { Console.ForegroundColor = ConsoleColor.White; Console.WriteLine(Environment.NewLine); Socket socket = (Socket)AR.AsyncState; int received = socket.EndReceive(AR); byte[] dataBuf = new byte[received]; Array.Copy(_buffer, dataBuf, received); string text = Encoding.ASCII.GetString(dataBuf); Console.WriteLine("Text received: " + Environment.NewLine + text); string responseKey = ""; string keyRaw = text.Split(new string[] { Environment.NewLine }, StringSplitOptions.None)[11].Split(new string[] { " " }, StringSplitOptions.None)[1] + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; using (SHA1 sha1 = SHA1.Create()) { byte[] hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(keyRaw)); responseKey = Convert.ToBase64String(hash); } String response = "HTTP/1.1 101 Switching Protocols" + Environment.NewLine + "Upgrade: websocket" + Environment.NewLine + "Connection: Upgrade" + Environment.NewLine + "Sec-WebSocket-Accept: " + responseKey + Environment.NewLine + Environment.NewLine + "Sec-WebSocket-Protocol: chat" + Environment.NewLine; Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("KEY: " + responseKey); Console.ForegroundColor = ConsoleColor.White; socket.BeginSend(System.Text.Encoding.UTF8.GetBytes(response), 0, System.Text.Encoding.UTF8.GetBytes(response).Length, SocketFlags.None, new AsyncCallback(SendCallback), socket); socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket); } catch (Exception e) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Error: " + e.Message); } } private static void SendCallback(IAsyncResult AR) { Socket socket = (Socket)AR.AsyncState; socket.EndSend(AR); } } }
Wenn ich nun den Java-Script ausführe, erhalte ich folgendes:
http://i.imgur.com/xPQAGCR.png
und als rückgabe vom js erhalte ich
- Open!
- Connection is closed...
index.php:9 ----> ws.send("text");
Auch wenn ich zu onopen ws.send("Hey"); hinzufüge, bekomme ich immer gleich danach onclose als Rückgabe.
Und in der Chrome-Console folgenden Error:
WebSocket is already in CLOSING or CLOSED state.ws.onopen @ index.php:9
Weiss jemand vielleicht was ich falsch mache? Oder was ich anders machen muss?
Wäre echt dankbar
mfG
Web-Tester
Beitrag zuletzt geändert: 6.7.2015 7:04:29 von web-tester -
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage
-
Wenn du diese Zeile im Serverprogramm entfernst:
Console.WriteLine("Text received: " + Environment.NewLine + text);
Bekommst du dann immernoch diesen Fehler in der Serverkonsole?
Error: Der Index war außerhalb des Arraybereichs.
Fall der Fehler immernoch kommt, dann versuche herauszufinden wo genau er entsteht.
(Es muss ja im try-Block von
passieren.ReceiveCallback
Fülle diesen Block also mit ganz vielen Ausgaben, um zu sehen, wie weit das Programm kommt. -
0) JScript ist eine Microsoft-Eigenheit, die du hier sicher nicht meinst. Also: JavaScript
1) Für HTTP ist ganz klar definiert, was ein Zeilenumbruch ist, und was nicht. Ein
hat beim Zusammensetzen des Headers also nichts verloren.Environment.NewLine
2) Fix die Position eines Headers anzugeben verstößt gegen die Protokoll-Spezifikation. Ein anderer Browser könnte das somit sehr einfach durcheinanderbringen.
3)
ist falsch, denn 2 Zeilenumbrüche beenden den Header, du schickst aber nachher noch etwas.+ "Sec-WebSocket-Accept: " + responseKey + Environment.NewLine + Environment.NewLine
4) Es gibt ein definiertes Frame-Format, an das du dich halten musst, wenn du etwas schicken willst. Siehe RFC. -
Danke für die schnellen Antworten
****EDIT***
So
Ich hab jetzt alle meine Fragen Antworten etc. gelöscht, nur zur Übersichtlichkeit.
Ich konnte alle meine Probleme lösen es funktioniert bis jetzt alles perfekt! Ein grosses Danke von mir ;)
Nur etwas wollte ich noch fragen:
Das ganze war nur möglich, da ich zufälligerweise auf einen Script gestossen bin:
public static byte[] getBytes(String mess) { byte[] rawData = Encoding.UTF8.GetBytes(mess); int frameCount = 0 byte[] frame = new byte[10] frame[0] = (byte)129 if (rawData.Length <= 125) { frame[1] = (byte)rawData.Length frameCount = 2 } else if (rawData.Length >= 126 && rawData.Length <= 65535) { frame[1] = (byte)126; int len = rawData.Length frame[2] = (byte)((len >?> 8) & (byte)255) frame[3] = (byte)(len & (byte)255) frameCount = 4 } else { frame[1] = (byte)127 int len = rawData.Length frame[2] = (byte)((len >> 56) & (byte)255) frame[3] = (byte)((len >> 48) & (byte)255) frame[4] = (byte)((len >> 40) & (byte)255) frame[5] = (byte)((len >> 32) & (byte)255) frame[6] = (byte)((len >> 24) & (byte)255) frame[7] = (byte)((len >> 16) & (byte)255) frame[8] = (byte)((len >> 8) & (byte)255) frame[9] = (byte)(len & (byte)255) frameCount = 10 } int bLength = frameCount + rawData.Length byte[] reply = new byte[bLength] int bLim = 0 for (int i = 0 i < frameCount; i++) { reply[bLim] = frame[i] bLim++ } for (int i = 0; i < rawData.Length; i++) { reply[bLim] = rawData[i] bLim++ } return reply }
Jetzt meine Frage, als ich eine Nachricht an den Client senden wollte, benutzte ich wie beim handshake System.Text.Encoding.UTF8.GetBytes(response). Wieso muss ich das jetzt hier mit einer solch komplizierten Funktion machen? Was macht sie anders?
Und geht es gut mit WebSockets aufwendigere Sachen, wie z.B. über 1000 Leute über den Server zu verbinden und dann jedem eine Nachricht schreiben? Oder sollte man da auf etwas anderes umsteigen?
Danke
web-tester
Beitrag zuletzt geändert: 7.7.2015 20:32:54 von web-tester -
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage