Je ne comprends pas pourquoi je ne peux pas faire fonctionner le code suivant. Je souhaite me connecter avec JavaScript à l'application de la console de mon serveur. Et ensuite envoyer des données au serveur.
Voici le code du serveur:
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));
}
}
et voici le 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...");
};
Quand je lance ce code, voici ce qui se passe:
Notez que lorsque je lance JavaScript, le serveur accepte et établit une connexion avec succès. JavaScript n'est pas capable d'envoyer des données cependant. Chaque fois que je mets la méthode d'envoi, elle n'enverra pas, même si une connexion est établie. Comment puis-je faire ce travail?
WebSockets est un protocole qui repose sur une connexion TCP en streaming. Bien que WebSockets soit basé sur le protocole Message.
Si vous souhaitez implémenter votre propre protocole, je vous recommande d'utiliser la dernière spécification stable (du 18/04/12) RFC 6455 . Cette spécification contient toutes les informations nécessaires sur la prise de contact et le cadrage. De plus, il est vivement recommandé de suivre les recommandations relatives au côté serveur lors de l’implémentation de votre code.
En quelques mots, je décrirais le travail avec WebSockets comme ceci:
Create server Socket} _ (System.Net.Sockets) le lie à un port spécifique et continue à écouter avec l'acceptation asynchrone des connexions. Quelque chose comme ca:
Socket serverSocket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP); ServerSocket.Bind (nouvel IPEndPoint (IPAddress.Any, 8080)); ServerSocket.Listen (128); serverSocket.BeginAccept (null, 0, OnAccept, null);
Vous devriez avoir la fonction accepter "OnAccept" qui implémentera la prise de contact. À l’avenir, il doit faire partie d’un autre thread si le système doit gérer un nombre considérable de connexions par seconde.
onAccept (résultat de IAsyncResult) { try { Socket client = null; if (serverSocket! = null && serverSocket.IsBound) { client = serverSocket.EndAccept (result); } if (client! = null) { /* Handshaking et gestion de ClientSocket */ } } catch (exception SocketException) { } finally { if (serverSocket! = null && serverSocket.IsBound) { serverSocket.BeginAccept (null, 0, OnAccept, null); } } }
Une fois la connexion établie, vous devez faire poignée de main. Sur la base de la spécification 1.3 Ouverture de la négociation , une fois la connexion établie, vous recevrez une requête HTTP de base avec certaines informations. Exemple:
GET/chat HTTP/1.1 Hôte: serveur.exemple.com Mise à niveau: websocket Connexion: Mise à niveau Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ == Origine: http: // exemple .com Sec-WebSocket-Protocol: discussion en ligne, superchat Sec-WebSocket-Version: 13
Cet exemple est basé sur la version du protocole 13. N'oubliez pas que les versions les plus anciennes présentent certaines différences, mais que la plupart des dernières versions sont compatibles entre elles. Différents navigateurs peuvent vous envoyer des données supplémentaires. Par exemple, les détails du navigateur et du système d'exploitation, le cache et autres.
Sur la base des détails de négociation fournis, vous devez générer des lignes de réponse, elles sont généralement identiques, mais contiendront Accpet-Key, qui est basée sur Sec-WebSocket-Key fournie. La spécification 1.3 décrit clairement comment générer la clé de réponse . Voici la fonction que j'utilise pour V13:
statique chaîne privée guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; chaîne privée AcceptKey (clé de chaîne de référence) { string longKey = clé + guid; SHA1 sha1 = SHA1CryptoServiceProvider.Create (); byte [] hashBytes = sha1.ComputeHash (System.Text.Encoding.ASCII.GetBytes (longKey)); return Convert.ToBase64String (hashBytes); }
Poignée de main réponse ressemble à ça:
HTTP/1.1 101 Protocoles de commutation Mise à niveau: websocket Connexion: Mise à niveau Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK + xOo =
Mais accepter clé doit être celle générée sur la base de la clé fournie par le client et de la méthode AcceptKey que j'ai fournie auparavant. De même, assurez-vous qu'après le dernier caractère de la clé d'acceptation, vous insériez deux nouvelles lignes "\ r\n\r\n".
En même temps, vous pouvez jeter un coup d'œil aux solutions prêtes à l'emploi que Google (encore) en a assez.
In same time you might have a look in ready to use solutions that google (again) have enough.
(Réponse affichée au nom du PO) .
Je suis capable d'envoyer des données maintenant. Ceci est ma nouvelle version du programme grâce à vos réponses et au code de @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>
Lorsque je lance ce code, je peux envoyer et recevoir des données du client et du serveur. Le seul problème est que les messages sont cryptés lorsqu'ils arrivent sur le serveur. Voici les étapes de fonctionnement du programme:
Notez comment le message du client est crypté.
Les WebSockets sont implémentés avec un protocole qui implique une poignée de main entre client et serveur . Je n'imagine pas qu'ils fonctionnent très bien comme des prises normales. Lisez le protocole et faites en sorte que votre application en parle. Vous pouvez également utiliser une bibliothèque WebSocket existante ou .Net4.5beta qui possède un WebSocket API .
Depuis que vous utilisez WebSocket, spender est correct. Après avoir reçu les données initiales du WebSocket, vous devez envoyer le message d'établissement de liaison à partir du serveur C # avant que toute information supplémentaire puisse circuler.
HTTP/1.1 101 Web Socket Protocol Handshake
Upgrade: websocket
Connection: Upgrade
WebSocket-Origin: example
WebSocket-Location: something.here
WebSocket-Protocol: 13
Quelque chose dans ce sens.
Vous pouvez faire quelques recherches supplémentaires sur le fonctionnement de WebSocket sur w3 ou google.
Voici une spécifcation de protocole: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76#section-1.3
Liste des exemples de travail:
Vous pouvez essayer ces exemples simples ...
Je ne pouvais pas trouver un exemple de travail simple n'importe où (à compter du 19 janvier), donc voici une version mise à jour J'ai la version chrome 71.0.3578.98.
Serveur Websocket C #:
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 et 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>