gpt4 book ai didi

c# - websocket 成功握手,但没有正确发送接收消息(C# 服务器)

转载 作者:太空狗 更新时间:2023-10-30 00:55:53 28 4
gpt4 key购买 nike

经过一上午的战斗,我的握手可以正常工作,但现在我无法真正发送和接收消息。我一直在寻找无济于事的答案,所以我想我终于站出来问了:/

到目前为止,我的客户非常简单:

function testWebSocket() {
if (!window.WebSocket) {
alert('WebSockets are NOT supported by your browser.');
return;
}

try {
var ws = new WebSocket('ws://localhost:8181/websession');
ws.onopen = function () {
alert('Handshake successfully established. Ready for data...');
};

ws.onmessage = function (e) {
alert('Got WebSockets message: ' + e.data);
}

ws.onclose = function () {
alert('Connection closed.');
};
}
catch (e) {
alert(e);
}
}

是的,我为此借用了很多代码...我只是想通过一个简单的“聊天应用程序”获得概念验证

我的服务器主要由两个类组成,SocketServer.cs 和 SocketClient.cs

他们遵循:

套接字服务器.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.IO;

namespace WebSocketServer.Entities
{
class SocketServer
{
public static Form1 parentForm;
TcpListener socketServer;
public static List<SocketClient> ClientList = new List<SocketClient>();


public SocketServer(Form1 pForm)
{

parentForm = pForm;
parentForm.ApplyText("Socket Class Initiated\r\n");
socketServer = new TcpListener(IPAddress.Any, 8181);
// tell the console that it's started
parentForm.ApplyText("Socket Server Started\r\n");

// create continuous loops to listen for new connections
// start the listener
socketServer.Start();
while (true)
{
// check for any incoming pending connections
// create new socket client for new connection
TcpClient socketConnection = socketServer.AcceptTcpClient();
DateTime now = DateTime.Now;
//write message to console to indicate new connection
parentForm.ApplyText("New Client Connected - " + now.ToString("MM/dd/yyyy h:mm:ss tt") + "\r\n");
// create new client object for this connection
SocketClient socketClient = new SocketClient(socketConnection, parentForm);
}
}

public static void CloseClient(SocketClient whichClient)
{
ClientList.Remove(whichClient);
whichClient.Client.Close();
// dispose of the client object
whichClient.Dispose();
whichClient = null;
parentForm.ApplyText("Client Disconnected\r\n");
}



public static void SendTextToClient(SocketClient sc, string text)
{
StreamWriter writer = new StreamWriter(sc.Client.GetStream());
// check if client is still connected, then send the text string
try
{
if (sc.Client.Connected)
{
writer.WriteLine(text);
writer.Flush();
writer = null;
}
}
catch
{
CloseClient(sc);
}

}


public static void SendBroadcast(string text)
{
StreamWriter writer;
// loop through the array and send text to all clients
foreach (SocketClient client in ClientList)
{
if (client.Client.Connected)
{
try
{
writer = new StreamWriter(client.Client.GetStream());
writer.WriteLine(text);
writer.Flush();
writer = null;

}
catch
{
CloseClient(client);
}
}
}
}
}
}

套接字客户端.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.IO;
using System.Threading;
using System.Security.Cryptography;

namespace WebSocketServer.Entities
{
class SocketClient
{
public TcpClient Client;
StreamReader reader;
StreamWriter writer;
Form1 parentForm;


public SocketClient(TcpClient client, Form1 pForm)
{
parentForm = pForm;
Client = client;
Thread clientThread = new Thread(new ThreadStart(StartClient));
clientThread.Start();
}


private void StartClient()
{
SocketServer.ClientList.Add(this);
// create a reader for this client
reader = new StreamReader(Client.GetStream());
// create a writer for this client
writer = new StreamWriter(Client.GetStream());

var headers = new Dictionary<string, string>();

string line = "";
while ((line = reader.ReadLine()) != string.Empty)
{
if (!string.IsNullOrEmpty(line))
{
var tokens = line.Split(new char[] { ':' }, 2);
if (!string.IsNullOrWhiteSpace(line) && tokens.Length > 1)
{
headers[tokens[0]] = tokens[1].Trim();
}
}
}


String secWebSocketAccept = ComputeWebSocketHandshakeSecurityHash09(headers["Sec-WebSocket-Key"]);

// send handshake to this client only
writer.WriteLine("HTTP/1.1 101 Web Socket Protocol Handshake");
writer.WriteLine("Upgrade: WebSocket");
writer.WriteLine("Connection: Upgrade");
writer.WriteLine("WebSocket-Origin: http://localhost:63422/");
writer.WriteLine("WebSocket-Location: ws://localhost:8181/websession");
writer.WriteLine("Sec-WebSocket-Accept: " + secWebSocketAccept);
writer.WriteLine("");
writer.Flush();

SocketServer.SendBroadcast("New Client Connected");

Thread clientRun = new Thread(new ThreadStart(RunClient));
clientRun.Start();
}

public static String ComputeWebSocketHandshakeSecurityHash09(String secWebSocketKey)
{
const String MagicKEY = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
String secWebSocketAccept = String.Empty;

// 1. Combine the request Sec-WebSocket-Key with magic key.
String ret = secWebSocketKey + MagicKEY;

// 2. Compute the SHA1 hash
SHA1 sha = new SHA1CryptoServiceProvider();
byte[] sha1Hash = sha.ComputeHash(Encoding.UTF8.GetBytes(ret));

// 3. Base64 encode the hash
secWebSocketAccept = Convert.ToBase64String(sha1Hash);

return secWebSocketAccept;
}


private void RunClient()
{
try
{
string line = "";
while (true)
{
line = reader.ReadLine();
if (!string.IsNullOrEmpty(line))
{
parentForm.ApplyText(line + "\r\n");
SocketServer.SendBroadcast(line);
}
}
}
catch
{
parentForm.ApplyText("Client Disconnected\r\n");
SocketServer.CloseClient(this);
}
}

public void Dispose()
{
System.GC.SuppressFinalize(this);
}
}

}

我可以在 Chrome 中连接多个实例,我的服务器显示所有连接的客户端,我看到握手成功的警报。但是当我尝试从客户端发送文本时(上面没有显示代码,但它是一个非常简单的 ws.send(text) 之类的东西),它以乱码文本的形式发送到服务器。当我尝试从服务器到客户端执行 writer.WriteLine("whatever") 时,onmessage 事件永远不会触发。在我终于解决了握手问题后,我环顾四周,但找不到任何解决此问题的好例子。

我不应该使用 StreamWriter 吗?我是否在握手时遗漏了其他内容(可能是协议(protocol))。

寻找和帮助的 TIA。

编辑:

下面的代码有效,但我不知道如何修改它以允许动态大小的文本长度。我现在可以发送 127 或更少的文本,但我似乎无法掌握如何超过 4。

public static void SendBroadcast(string text)
{
StreamWriter writer;
// loop through the array and send text to all clients
foreach (SocketClient client in ClientList)
{
if (client.Client.Connected)
{
try
{
NetworkStream l_Stream = client.Client.GetStream();
List<byte> lb = new List<byte>();
lb.Add(0x81);
lb.Add(0x04);
lb.AddRange(Encoding.UTF8.GetBytes("test"));
l_Stream.Write(lb.ToArray(), 0, 6);
}
catch
{
CloseClient(client);
}
}
}
}

我试过将 lb.Add(0x04) 修改为 lb.Add(0x07) 并且不发送“测试”骰子。我也对 l_Stream.Write() 参数是什么感到困惑。我知道它是字节数组、偏移量和大小,但大小是多少?

最佳答案

在最新版本的规范中,消息不会以纯文本形式发送。查看data framing section了解详情。

wiki post也很有帮助。

我还写了一个C++ server ; WsProtocol80 类展示了如何读取/写入数据。

编辑:在您的示例发送代码中,0x04 字节指定了一条 4 字节的消息。您可以通过这种方式设置不同的值并发送最多 125 个字节的消息。当您更改消息长度时,您还必须将最后一个参数更新为 l_Stream.Write(它指定要写入的字节数)。在所有情况下将其更改为 lb.Count 似乎更好。

如果您仍然觉得按位运算令人困惑,并且以后想要发送更长的消息或从客户端读取消息,则上面指向 wiki 帖子的链接包含应该有用的伪代码。

关于c# - websocket 成功握手,但没有正确发送接收消息(C# 服务器),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9087168/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com