Ich verstehe nicht, warum ich den folgenden Code nicht zum Laufen bringen kann. Ich möchte mit JavaScript eine Verbindung zu meiner Serverkonsolenanwendung herstellen. Und dann Daten an den Server senden.
Hier ist der Servercode:
static void Main(string[] args)
{
TcpListener server = new TcpListener(IPAddress.Parse("127.0.0.1"), 9998);
server.Start();
var client = server.AcceptTcpClient();
var stream = client.GetStream();
while (true)
{
var buffer = new byte[1024];
// wait for data to be received
var bytesRead = stream.Read(buffer, 0, buffer.Length);
var r = System.Text.Encoding.UTF8.GetString(buffer);
// write received data to the console
Console.WriteLine(r.Substring(0, bytesRead));
}
}
und hier ist das JavaScript:
var ws = new WebSocket("ws://localhost:9998/service");
ws.onopen = function () {
ws.send("Hello World"); // I WANT TO SEND THIS MESSAGE TO THE SERVER!!!!!!!!
};
ws.onmessage = function (evt) {
var received_msg = evt.data;
alert("Message is received...");
};
ws.onclose = function () {
// websocket is closed.
alert("Connection is closed...");
};
Wenn ich diesen Code ausführe, passiert Folgendes:
Beachten Sie, dass der Server beim Ausführen von JavaScript eine Verbindung akzeptiert und erfolgreich herstellt. JavaScript kann jedoch keine Daten senden. Immer wenn ich die Sendemethode platziere, wird sie nicht gesendet, obwohl eine Verbindung hergestellt wurde. Wie kann ich diese Arbeit machen?
WebSockets ist ein Protokoll, das auf einer TCP gestreamten Verbindung basiert. Obwohl WebSockets ein Message-basiertes Protokoll ist.
Wenn Sie ein eigenes Protokoll implementieren möchten, empfehle ich die Verwendung der neuesten und stabilen Spezifikation (für 18/04/12) RFC 6455 . Diese Spezifikation enthält alle erforderlichen Informationen zu Handshake und Framing. Die meisten Beschreibungen zu Szenarien des Verhaltens sowohl auf der Browserseite als auch auf der Serverseite . Es wird dringend empfohlen, die Empfehlungen bezüglich der Serverseite während der Implementierung Ihres Codes zu befolgen.
In wenigen Worten würde ich die Arbeit mit WebSockets folgendermaßen beschreiben:
Server-Socket erstellen (System.Net.Sockets) binden Sie es an einen bestimmten Port und überwachen Sie es weiterhin, indem Sie asynchrone Verbindungen annehmen. Sowas in der Art:
Socket serverSocket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP); ServerSocket.Bind (new IPEndPoint (IP-Adresse.Any, 8080)); ServerSocket.Listen (128); serverSocket.BeginAccept (null, 0, OnAccept, null);
Sie sollten Annehmen Funktion "OnAccept" haben, die Handshake implementiert. In Zukunft muss es in einem anderen Thread sein, wenn das System eine große Anzahl von Verbindungen pro Sekunde verarbeiten soll.
private void OnAccept (IAsyncResult-Ergebnis) { try { Socket-Client = null; if (serverSocket! = null && serverSocket.IsBound) { Client = ServerSocket.EndAccept (Ergebnis); } if (client! = null) { /* Handshaking und Verwalten von ClientSocket */ } } catch (SocketException-Ausnahme) { } Schließlich { if (serverSocket! = null && serverSocket.IsBound) { serverSocket.BeginAccept (null, 0, OnAccept, null); } } }
Nachdem die Verbindung hergestellt wurde, müssen Sie Handshake ausführen. Basierend auf den Angaben 1.3 Opening Handshake erhalten Sie nach dem Herstellen der Verbindung eine grundlegende HTTP-Anforderung mit einigen Informationen. Beispiel:
GET/chat HTTP/1.1 Host: server.example.com Upgrade: Websocket Verbindung: Upgrade Sec-WebSocket-Schlüssel: dGhlIHNhbXBsZSBub25jZQ == Ursprung: http: // .com Sec-WebSocket-Protokoll: chat, superchat Sec-WebSocket-Version: 13
Dieses Beispiel basiert auf der Version des Protokolls 13. Beachten Sie, dass ältere Versionen einige Unterschiede aufweisen, die meisten aktuellen Versionen jedoch kreuzkompatibel sind. Verschiedene Browser senden Ihnen möglicherweise zusätzliche Daten. Zum Beispiel Browser- und Betriebssystemdetails, Cache und andere.
Basierend auf den angegebenen Handshake-Details müssen Sie Antwortzeilen generieren, die größtenteils gleich sind, jedoch den Accpet-Key enthalten, der auf dem bereitgestellten Sec-WebSocket-Key basiert. In Spezifikation 1.3 wird klar beschrieben, wie der Antwortschlüssel generiert wird .. Hier ist meine Funktion, die ich für V13 verwendet habe:
statische private Zeichenfolge guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; private Zeichenfolge AcceptKey (Referenzzeichenfolge) { Zeichenfolge longKey = key + guid; SHA1 sha1 = SHA1CryptoServiceProvider.Create (); byte [] hashBytes = sha1.ComputeHash (System.Text.Encoding.ASCII.GetBytes (longKey)); return Convert.ToBase64String (hashBytes); }
Die Handshake-Antwort sieht so aus:
HTTP/1.1 101 Wechseln der Protokolle Upgrade: Websocket Verbindung: Upgrade Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK + xOo =
Der Accept-Schlüssel muss jedoch der generierte Schlüssel sein, der auf dem vom Client und der Methode AcceptKey I bereitgestellten Schlüssel basiert. Stellen Sie außerdem sicher, dass Sie nach dem letzten Zeichen der Übernahmetaste zwei neue Zeilen "\ r\n\r\n" einfügen.
In der gleichen Zeit können Sie einen Blick auf die gebrauchsfertigen Lösungen werfen, die Google (wieder) genug hat.
In same time you might have a look in ready to use solutions that google (again) have enough.
(Gepostete Antwort im Namen des OP) .
Ich kann jetzt Daten senden. Dies ist meine neue Version des Programms dank Ihrer Antworten und des Codes von @Maksims Mihejevs.
using System;
using System.Net.Sockets;
using System.Net;
using System.Security.Cryptography;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static Socket serverSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.IP);
static private string guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
static void Main(string[] args)
{
serverSocket.Bind(new IPEndPoint(IPAddress.Any, 8080));
serverSocket.Listen(128);
serverSocket.BeginAccept(null, 0, OnAccept, null);
Console.Read();
}
private static void OnAccept(IAsyncResult result)
{
byte[] buffer = new byte[1024];
try
{
Socket client = null;
string headerResponse = "";
if (serverSocket != null && serverSocket.IsBound)
{
client = serverSocket.EndAccept(result);
var i = client.Receive(buffer);
headerResponse = (System.Text.Encoding.UTF8.GetString(buffer)).Substring(0,i);
// write received data to the console
Console.WriteLine(headerResponse);
}
if (client != null)
{
/* Handshaking and managing ClientSocket */
var key = headerResponse.Replace("ey:", "`")
.Split('`')[1] // dGhlIHNhbXBsZSBub25jZQ== \r\n .......
.Replace("\r", "").Split('\n')[0] // dGhlIHNhbXBsZSBub25jZQ==
.Trim();
// key should now equal dGhlIHNhbXBsZSBub25jZQ==
var test1 = AcceptKey(ref key);
var newLine = "\r\n";
var response = "HTTP/1.1 101 Switching Protocols" + newLine
+ "Upgrade: websocket" + newLine
+ "Connection: Upgrade" + newLine
+ "Sec-WebSocket-Accept: " + test1 + newLine + newLine
//+ "Sec-WebSocket-Protocol: chat, superchat" + newLine
//+ "Sec-WebSocket-Version: 13" + newLine
;
// which one should I use? none of them fires the onopen method
client.Send(System.Text.Encoding.UTF8.GetBytes(response));
var i = client.Receive(buffer); // wait for client to send a message
// once the message is received decode it in different formats
Console.WriteLine(Convert.ToBase64String(buffer).Substring(0, i));
Console.WriteLine("\n\nPress enter to send data to client");
Console.Read();
var subA = SubArray<byte>(buffer, 0, i);
client.Send(subA);
Thread.Sleep(10000);//wait for message to be send
}
}
catch (SocketException exception)
{
throw exception;
}
finally
{
if (serverSocket != null && serverSocket.IsBound)
{
serverSocket.BeginAccept(null, 0, OnAccept, null);
}
}
}
public static T[] SubArray<T>(T[] data, int index, int length)
{
T[] result = new T[length];
Array.Copy(data, index, result, 0, length);
return result;
}
private static string AcceptKey(ref string key)
{
string longKey = key + guid;
byte[] hashBytes = ComputeHash(longKey);
return Convert.ToBase64String(hashBytes);
}
static SHA1 sha1 = SHA1CryptoServiceProvider.Create();
private static byte[] ComputeHash(string str)
{
return sha1.ComputeHash(System.Text.Encoding.ASCII.GetBytes(str));
}
}
}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script type="text/javascript">
function connect() {
var ws = new WebSocket("ws://localhost:8080/service");
ws.onopen = function () {
alert("About to send data");
ws.send("Hello World"); // I WANT TO SEND THIS MESSAGE TO THE SERVER!!!!!!!!
alert("Message sent!");
};
ws.onmessage = function (evt) {
alert("About to receive data");
var received_msg = evt.data;
alert("Message received = "+received_msg);
};
ws.onclose = function () {
// websocket is closed.
alert("Connection is closed...");
};
};
</script>
</head>
<body style="font-size:xx-large" >
<div>
<a href="#" onclick="connect()">Click here to start</a></div>
</body>
</html>
Wenn ich diesen Code ausführen, kann ich Daten sowohl vom Client als auch vom Server senden und empfangen. Das einzige Problem ist, dass die Nachrichten verschlüsselt werden, wenn sie beim Server ankommen. Hier sind die Schritte, wie das Programm läuft:
Beachten Sie, wie die Nachricht vom Client verschlüsselt wird.
WebSockets werden mit einem Protokoll implementiert , das Handshake zwischen Client und Server beinhaltet. Ich kann mir nicht vorstellen, dass sie wie normale Steckdosen funktionieren. Informieren Sie sich über das Protokoll und lassen Sie Ihre Anwendung darüber sprechen. Verwenden Sie alternativ eine vorhandene WebSocket-Bibliothek oder .Net4.5beta, die über eine WebSocket-API verfügt.
Da Sie WebSocket verwenden, ist Spender korrekt. Nachdem Sie die ursprünglichen Daten von WebSocket erhalten haben, müssen Sie die Handshake-Nachricht vom C # -Server senden, bevor weitere Informationen übertragen werden können.
HTTP/1.1 101 Web Socket Protocol Handshake
Upgrade: websocket
Connection: Upgrade
WebSocket-Origin: example
WebSocket-Location: something.here
WebSocket-Protocol: 13
Etwas in diese Richtung.
Sie können weitere Untersuchungen zur Funktionsweise von WebSocket auf W3 oder Google durchführen.
Hier ist eine Protokollspezifikation: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-###-1.3
Liste der Arbeitsbeispiele:
Sie können diese einfachen Beispiele ausprobieren ...
Ich konnte nirgendwo ein einfaches Arbeitsbeispiel finden (ab 19. Januar), daher hier eine aktualisierte Version. Ich habe Chromversion 71.0.3578.98.
C # Websocket-Server:
using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;
namespace WebSocketServer
{
class Program
{
static Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
static private string guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
static void Main(string[] args)
{
serverSocket.Bind(new IPEndPoint(IPAddress.Any, 8080));
serverSocket.Listen(1); //just one socket
serverSocket.BeginAccept(null, 0, OnAccept, null);
Console.Read();
}
private static void OnAccept(IAsyncResult result)
{
byte[] buffer = new byte[1024];
try
{
Socket client = null;
string headerResponse = "";
if (serverSocket != null && serverSocket.IsBound)
{
client = serverSocket.EndAccept(result);
var i = client.Receive(buffer);
headerResponse = (System.Text.Encoding.UTF8.GetString(buffer)).Substring(0, i);
// write received data to the console
Console.WriteLine(headerResponse);
Console.WriteLine("=====================");
}
if (client != null)
{
/* Handshaking and managing ClientSocket */
var key = headerResponse.Replace("ey:", "`")
.Split('`')[1] // dGhlIHNhbXBsZSBub25jZQ== \r\n .......
.Replace("\r", "").Split('\n')[0] // dGhlIHNhbXBsZSBub25jZQ==
.Trim();
// key should now equal dGhlIHNhbXBsZSBub25jZQ==
var test1 = AcceptKey(ref key);
var newLine = "\r\n";
var response = "HTTP/1.1 101 Switching Protocols" + newLine
+ "Upgrade: websocket" + newLine
+ "Connection: Upgrade" + newLine
+ "Sec-WebSocket-Accept: " + test1 + newLine + newLine
//+ "Sec-WebSocket-Protocol: chat, superchat" + newLine
//+ "Sec-WebSocket-Version: 13" + newLine
;
client.Send(System.Text.Encoding.UTF8.GetBytes(response));
var i = client.Receive(buffer); // wait for client to send a message
string browserSent = GetDecodedData(buffer, i);
Console.WriteLine("BrowserSent: " + browserSent);
Console.WriteLine("=====================");
//now send message to client
client.Send(GetFrameFromString("This is message from server to client."));
System.Threading.Thread.Sleep(10000);//wait for message to be sent
}
}
catch (SocketException exception)
{
throw exception;
}
finally
{
if (serverSocket != null && serverSocket.IsBound)
{
serverSocket.BeginAccept(null, 0, OnAccept, null);
}
}
}
public static T[] SubArray<T>(T[] data, int index, int length)
{
T[] result = new T[length];
Array.Copy(data, index, result, 0, length);
return result;
}
private static string AcceptKey(ref string key)
{
string longKey = key + guid;
byte[] hashBytes = ComputeHash(longKey);
return Convert.ToBase64String(hashBytes);
}
static SHA1 sha1 = SHA1CryptoServiceProvider.Create();
private static byte[] ComputeHash(string str)
{
return sha1.ComputeHash(System.Text.Encoding.ASCII.GetBytes(str));
}
//Needed to decode frame
public static string GetDecodedData(byte[] buffer, int length)
{
byte b = buffer[1];
int dataLength = 0;
int totalLength = 0;
int keyIndex = 0;
if (b - 128 <= 125)
{
dataLength = b - 128;
keyIndex = 2;
totalLength = dataLength + 6;
}
if (b - 128 == 126)
{
dataLength = BitConverter.ToInt16(new byte[] { buffer[3], buffer[2] }, 0);
keyIndex = 4;
totalLength = dataLength + 8;
}
if (b - 128 == 127)
{
dataLength = (int)BitConverter.ToInt64(new byte[] { buffer[9], buffer[8], buffer[7], buffer[6], buffer[5], buffer[4], buffer[3], buffer[2] }, 0);
keyIndex = 10;
totalLength = dataLength + 14;
}
if (totalLength > length)
throw new Exception("The buffer length is small than the data length");
byte[] key = new byte[] { buffer[keyIndex], buffer[keyIndex + 1], buffer[keyIndex + 2], buffer[keyIndex + 3] };
int dataIndex = keyIndex + 4;
int count = 0;
for (int i = dataIndex; i < totalLength; i++)
{
buffer[i] = (byte)(buffer[i] ^ key[count % 4]);
count++;
}
return Encoding.ASCII.GetString(buffer, dataIndex, dataLength);
}
//function to create frames to send to client
/// <summary>
/// Enum for opcode types
/// </summary>
public enum EOpcodeType
{
/* Denotes a continuation code */
Fragment = 0,
/* Denotes a text code */
Text = 1,
/* Denotes a binary code */
Binary = 2,
/* Denotes a closed connection */
ClosedConnection = 8,
/* Denotes a ping*/
Ping = 9,
/* Denotes a pong */
Pong = 10
}
/// <summary>Gets an encoded websocket frame to send to a client from a string</summary>
/// <param name="Message">The message to encode into the frame</param>
/// <param name="Opcode">The opcode of the frame</param>
/// <returns>Byte array in form of a websocket frame</returns>
public static byte[] GetFrameFromString(string Message, EOpcodeType Opcode = EOpcodeType.Text)
{
byte[] response;
byte[] bytesRaw = Encoding.Default.GetBytes(Message);
byte[] frame = new byte[10];
int indexStartRawData = -1;
int length = bytesRaw.Length;
frame[0] = (byte)(128 + (int)Opcode);
if (length <= 125)
{
frame[1] = (byte)length;
indexStartRawData = 2;
}
else if (length >= 126 && length <= 65535)
{
frame[1] = (byte)126;
frame[2] = (byte)((length >> 8) & 255);
frame[3] = (byte)(length & 255);
indexStartRawData = 4;
}
else
{
frame[1] = (byte)127;
frame[2] = (byte)((length >> 56) & 255);
frame[3] = (byte)((length >> 48) & 255);
frame[4] = (byte)((length >> 40) & 255);
frame[5] = (byte)((length >> 32) & 255);
frame[6] = (byte)((length >> 24) & 255);
frame[7] = (byte)((length >> 16) & 255);
frame[8] = (byte)((length >> 8) & 255);
frame[9] = (byte)(length & 255);
indexStartRawData = 10;
}
response = new byte[indexStartRawData + length];
int i, reponseIdx = 0;
//Add the frame bytes to the reponse
for (i = 0; i < indexStartRawData; i++)
{
response[reponseIdx] = frame[i];
reponseIdx++;
}
//Add the data bytes to the response
for (i = 0; i < length; i++)
{
response[reponseIdx] = bytesRaw[i];
reponseIdx++;
}
return response;
}
}
}
Client HTML und Javascript:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script type="text/javascript">
var socket = new WebSocket('ws://localhost:8080/websession');
socket.onopen = function() {
// alert('handshake successfully established. May send data now...');
socket.send("Hi there from browser.");
};
socket.onmessage = function (evt) {
//alert("About to receive data");
var received_msg = evt.data;
alert("Message received = "+received_msg);
};
socket.onclose = function() {
alert('connection closed');
};
</script>
</head>
<body>
</body>
</html>