我试图将我的HTML / JS客户端连接到我的C#服务器,作为大学项目的一部分,以便允许用户实时通知。 (我只需要服务器能够在任何给定时间向特定用户发送消息)
我的服务器只是一个模拟器,以便在我的项目中实现它。
我成功通过了握手阶段,我正在尝试从服务器向客户端发送一个纯字符串。我读了一些关于编码消息的方法,客户端不会给出“一个或多个保留位打开:reserved1 = 0,reserved2 = 1,reserved3 = 1”错误但没有成功。
如何通过套接字发送原始数据并在客户端上对其进行解码?
我的服务器代码:
while (true)
{
TcpListener sck = new TcpListener(IPAddress.Any, 7878);
sck.Start(1000);
TcpClient client = sck.AcceptTcpClient();
NetworkStream _stream = client.GetStream();
StreamReader clientStreamReader = new StreamReader(_stream);
StreamWriter clientStreamWriter = new StreamWriter(_stream);
while (true)
{
while (!_stream.DataAvailable) ;
Byte[] bytes = new Byte[client.Available];
_stream.Read(bytes, 0, bytes.Count());
String data = Encoding.UTF8.GetString(bytes);
if (Regex.IsMatch(data, "^GET"))
{
const string eol = "\r\n"; // HTTP/1.1 defines the sequence CR LF as the end-of-line marker
Byte[] response = Encoding.UTF8.GetBytes("HTTP/1.1 101 Switching Protocols" + eol
+ "Connection: Upgrade" + eol
+ "Upgrade: websocket" + eol
+ "Sec-WebSocket-Accept: " + Convert.ToBase64String(
System.Security.Cryptography.SHA1.Create().ComputeHash(
Encoding.UTF8.GetBytes(
new System.Text.RegularExpressions.Regex("Sec-WebSocket-Key: (.*)").Match(data).Groups[1].Value.Trim() + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
)
)
) + eol
+ eol);
_stream.Write(response, 0, response.Length);
}
else
{
}
}
}
我的客户代码:
<script type="text/javascript">
function WebSocketTest() {
if ("WebSocket" in window) {
alert("WebSocket is supported by your Browser!");
// Let us open a web socket
var ws = new WebSocket("ws://localhost:7878");
ws.onopen = function () {
// Web Socket is connected, send data using send()
ws.send("Message to send");
alert("Message is sent...");
};
ws.onmessage = function (evt) {
var received_msg = evt.data;
alert("Message is received...");
};
ws.onclose = function () {
// websocket is closed.
alert("Connection is closed...");
};
} else {
// The browser doesn't support WebSocket
alert("WebSocket NOT supported by your Browser!");
}
}
</script>
答案 0 :(得分:1)
我保留了我的服务器,但添加了一个发送字符串函数和一个解码消息函数:
public static string DecodeMessage(Byte[] bytes)
{
string incomingData = string.Empty;
byte secondByte = bytes[1];
int dataLength = secondByte & 127;
int indexFirstMask = 2;
if (dataLength == 126)
indexFirstMask = 4;
else if (dataLength == 127)
indexFirstMask = 10;
IEnumerable<byte> keys = bytes.Skip(indexFirstMask).Take(4);
int indexFirstDataByte = indexFirstMask + 4;
byte[] decoded = new byte[bytes.Length - indexFirstDataByte];
for (int i = indexFirstDataByte, j = 0; i < bytes.Length; i++, j++)
{
decoded[j] = (byte)(bytes[i] ^ keys.ElementAt(j % 4));
}
return Encoding.UTF8.GetString(decoded, 0, decoded.Length);
}
public static void SendString(string userName ,string str)
{
if (!userConnections.ContainsKey(userName))
return;
TcpClient client = userConnections[userName];
NetworkStream _stream = client.GetStream();
try
{
var buf = Encoding.UTF8.GetBytes(str);
int frameSize = 64;
var parts = buf.Select((b, i) => new { b, i })
.GroupBy(x => x.i / (frameSize - 1))
.Select(x => x.Select(y => y.b).ToArray())
.ToList();
for (int i = 0; i < parts.Count; i++)
{
byte cmd = 0;
if (i == 0) cmd |= 1;
if (i == parts.Count - 1) cmd |= 0x80;
_stream.WriteByte(cmd);
_stream.WriteByte((byte)parts[i].Length);
_stream.Write(parts[i], 0, parts[i].Length);
}
_stream.Flush();
}
catch (Exception ex)
{
Console.WriteLine("Error");
}
}
其中userConnections是:public static Dictionary userConnections = new Dictionary(); 为了维护用户 - 连接关系
答案 1 :(得分:0)
您可以使用SuperWebSocket,此库会自动发送握手。
服务器:
using SuperSocket.SocketBase;
using SuperWebSocket;
using System;
using System.Net;
using System.Net.Sockets;
namespace Jees.Library.WebSocket
{
public class WebSocket
{
WebSocketServer appServer;
public event EventHandler ServerStarted;
public event EventHandler ServerStopped;
public event EventHandler MessageReceived;
public string IP { get; } = string.Empty;
public int Port { get; } = 1337; //change this to the port you want to use
public WebSocket() => this.IP = GetLocalIPAddress(); //or set it manually
public void Start()
{
appServer = new WebSocketServer();
if (!appServer.Setup(this.IP, this.Port))
{
this.OnServerStarted(new WebSocketServerEventArgs(false));
return;
}
/* start listening */
appServer.NewMessageReceived += new SessionHandler<WebSocketSession, string>(AppServer_NewMessageReceived);
if (appServer.Start())
this.OnServerStarted(new WebSocketServerEventArgs(true));
else
{
this.OnServerStarted(new WebSocketServerEventArgs(false));
appServer = null;
appServer.Dispose();
}
}
public void Stop()
{
if (appServer != null)
{
appServer.Stop();
this.OnServerStopped(new EventArgs());
appServer = null;
appServer.Dispose();
}
}
private void AppServer_NewMessageReceived(WebSocketSession session, string message)
{
this.OnMessageReceived(new MessageReceivedEventArgs(message, session));
}
protected virtual void OnMessageReceived(EventArgs e) => this.MessageReceived?.Invoke(this, e);
protected virtual void OnServerStarted(EventArgs e) => this.ServerStarted?.Invoke(this, e);
protected virtual void OnServerStopped(EventArgs e) => this.ServerStopped?.Invoke(this, e);
private string GetLocalIPAddress()
{
var host = Dns.GetHostEntry(Dns.GetHostName());
foreach (var ip in host.AddressList)
if (ip.AddressFamily == AddressFamily.InterNetwork)
return ip.ToString();
throw new Exception("No network adapters with an IPv4 address in the system!");
}
}
public class WebSocketServerEventArgs : EventArgs
{
public WebSocketServerEventArgs(bool success) => this.Success = success;
public bool Success { get; }
}
public class MessageReceivedEventArgs : EventArgs
{
public MessageReceivedEventArgs(string message, WebSocketSession session)
{
this.Message = message;
this.Session = session;
}
public string Message { get; }
public WebSocketSession Session { get; }
}
}
服务器设置(我使用UserControl
):
using DevExpress.XtraEditors;
using SuperWebSocket;
using System;
using System.Linq;
using System.Windows.Forms;
namespace WebSocketServer
{
public partial class Server : UserControl
{
WebSocket server;
WebSocketSession session;
public Server()
{
InitializeComponent();
server = new WebSocket();
server.ServerStarted += Server_ServerStarted;
server.ServerStopped += Server_ServerStopped;
server.MessageReceived += Server_MessageReceived;
}
private void Server_MessageReceived(object sender, EventArgs e)
{
MessageReceivedEventArgs eventArgs = (MessageReceivedEventArgs)e;
/* save session */
this.session = eventArgs.Session;
this.Log("SessionID: " + session.RemoteEndPoint.ToString() + "; Message: " + eventArgs.Message);
/* send back the message to the client */
this.session.Send(eventArgs.Message); //comment out if needed
}
private void Server_ServerStopped(object sender, EventArgs e)
{
this.Log("Server stopped!");
}
private void Server_ServerStarted(object sender, EventArgs e)
{
if ((e as WebSocketServerEventArgs).Success)
{
this.Log("Server started on ws://" + server.IP + ":" + server.Port + "/");
}
else
this.Log("Can't start the server!");
}
private void Log(string message)
{
/* here, this.log is a TextBox */
if (this.log.InvokeRequired)
this.log.Invoke((MethodInvoker)delegate
{
this.log.Text += DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss") + " > " + message + Environment.NewLine;
});
else
{
this.log.Text += DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss") + " > " + message + Environment.NewLine;
}
}
/* a button to start the server */
private void BtnStart_Click(object sender, EventArgs e) => server.Start();
/* a button to stop the server */
private void BtnStop_Click(object sender, EventArgs e) => server.Stop();
/* a button to send a message from a TextBox to the client */
private void BtnSend_Click(object sender, EventArgs e)
{
if (this.txtMessage.Text != string.Empty)
this.SendMessage(this.txtMessage.Text);
}
private void SendMessage(string message)
{
try
{
/* use current session to send the message */
this.session.Send(message);
this.Log("Message: " + message + " sent to client!");
}
catch (Exception e)
{
this.Log(e.Message);
}
}
}
}
如果您需要更多说明,请添加评论,我会更新我的回答!