.NET 基于Socket中转WebSocket

news/2024/10/11 13:01:28/

前言

针对IOS App Proxy Server无法直连WebSocket,建立 Socket中转端。

WebSocket

WebSocket 端用于实现实时通信功能。

WebSocket 端通过 WebSocket 协议与中转端通信,中转端可以通过 WebSocket 或其他传输协议与 WebSocket 端建立连接,收发消息。

定义 SendMessageToChatRoomIP 和 JoinChatRoom,用于处理来自客户端的消息和连接事件。

中转端 C1 (Socket Server)

中转端 C1 是一个独立的应用程序,用于连接WebSocket端,建立Socket服务。

中转端 C1 的主要功能是接收来自客户端 C2 的消息,并将其转发给 WebSocket 端,或者接收来自 WebSocket 端的消息,并转发给客户端 C2。

客户端 C2 x  N

客户端 C2 ,主要与中转端连接 发送数据,接收数据。

在客户端 C2 中,连接到中转端 C1、发送消息给中转端 C1、接收来自中转端 C1 的消息。

调用关系为:

客户端 C2 通过与中转端 C1 的通信,向 WebSocket 端发送消息或接收来自 WebSocket 端的消息。

中转端 C1 接收来自客户端 C2 的消息,并将其转发给 WebSocket 端,或者接收来自 WebSocket 端的消息,并转发给客户端 C2。

中转端实现

1.连接WebSocket

      public async Task ConnectToServer(){try{connection = new HubConnectionBuilder().WithUrl("xxx/chathub")//.Build();connection.On<string, string, string, string>("ReceiveMessage", async (user, message, clientIP, chatRoomId) =>{Console.WriteLine($"Received message from wsserver_sr : {user}: {message} |socketserver {clientIP}|{chatRoomId}");// 收到来自服务器的消息时,向客户端 C2 发送消息await SendMessageToClientC2(user, message, clientIP, chatRoomId);});await connection.StartAsync();}catch (Exception ex){Console.WriteLine($"Error connecting to SignalR server: {ex.Message}" + Environment.NewLine);}}

 收到消息时发送给对应客户端

       public async Task SendMessageToClientC2(string user, string message, string clientIP, string chatRoomId){// 根据 chatRoomId 找到对应的客户端 C2,并发送消息if (chatRooms.ContainsKey(chatRoomId)){byte[] data = Encoding.ASCII.GetBytes($"{user}  {message}  |{clientIP}|{chatRoomId} ");foreach (var client in chatRooms[chatRoomId]){await client.GetStream().WriteAsync(data, 0, data.Length);}}else{Console.WriteLine($"Chat room {chatRoomId} does not exist" + Environment.NewLine);}}

2.建立中转端Socket端口

   public void StartListening(){if (!listening){try{int port = 10086; // 监听端口server = new TcpListener(IPAddress.Any, port);server.Start();listening = true;Console.WriteLine($"Server listening on port {port}" + Environment.NewLine);Task.Run(() => AcceptClients());}catch (Exception ex){Console.WriteLine($"Error starting server: {ex.Message}" + Environment.NewLine);}}}

3.向客户端发消息

public async Task AcceptClients(){while (listening){try{TcpClient client = await server.AcceptTcpClientAsync();Task.Run(() => HandleClient(client));}catch (Exception ex){Console.WriteLine($"Error accepting client: {ex.Message}" + Environment.NewLine);}}}

4.监听客户端连接

   public async Task AcceptClients(){while (listening){try{TcpClient client = await server.AcceptTcpClientAsync();Task.Run(() => HandleClient(client));}catch (Exception ex){Console.WriteLine($"Error accepting client: {ex.Message}" + Environment.NewLine);}}}

5.处理客户端连接

    public async Task HandleClient(TcpClient client){NetworkStream stream = client.GetStream();byte[] buffer = new byte[1024];int bytesRead;while (client.Connected){try{bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);string message = Encoding.ASCII.GetString(buffer, 0, bytesRead);ProcessMessage(message, client);}catch (Exception ex){Console.WriteLine($"Error receiving message: {ex.Message}" + Environment.NewLine);break;}}// 客户端断开连接时,从聊天室中移除foreach (var chatRoomId in chatRooms.Keys){if (chatRooms[chatRoomId].Contains(client)){chatRooms[chatRoomId].Remove(client);Console.WriteLine($"Client disconnected from chat room {chatRoomId}" + Environment.NewLine);break;}}}

6.处理连接

        public async void ProcessMessage(string message, TcpClient client){string[] parts = message.Split('|');if (parts.Length >= 2){string command = parts[0];string chatRoomId = parts[1];switch (command){case "JoinChatRoom":await JoinChatRoom(chatRoomId, client);break;case "SendMessageToChatRoomIP2":if (parts.Length >= 4){string user = parts[2];string msg = parts[3];//  await SendMessageToChatRoom(chatRoomId, user, msg);await SendMessageToChatRoomAddress(chatRoomId, user, msg, client);}break;default:Console.WriteLine($"Invalid command: {command}" + Environment.NewLine);break;}}}

JoinChatRoom 异步调用服务端的JoinChatRoom 

SendMessageToChatRoomIP2 异步调用SendMessage  

7.运行

本地运行

发布到linux

run  Server listening on port 10860

netstat -tln查看端口 (tuln) 

也可以优化封装成WinForm程序,收发消息可视化。

点击启动socket端口调用 1.连接websocket 2.监听socket   

也可以封装成系统服务,与进程一样藏在后台运行。

客户端实现

1.连接Socket端

   private async void MainForm_Load(object sender, EventArgs e){try{client = new TcpClient();await client.ConnectAsync("192.168.80.123", 10086); stream = client.GetStream();connected = true;// 连接成功后,调用 JoinChatRoom 方法加入聊天室await JoinChatRoom("room001");Task.Run(ReceiveMessages);}catch (Exception ex){textBoxReceivedMessages.AppendText($"Error connecting to server: {ex.Message}" + Environment.NewLine);}}

 2.加入ChatRoom

JoinChatRoom中转到Server端再加入聊天室

   private async Task JoinChatRoom(string chatRoomId){// 发送消息给中转端 C1,请求加入聊天室byte[] data = Encoding.ASCII.GetBytes($"JoinChatRoom|{chatRoomId}|J");await stream.WriteAsync(data, 0, data.Length);}

3.发送消息

发送到Socket中转端

     private async Task SendMessageToChatRoom(string chatRoomId, string message){// 发送消息给中转端 C1,请求向指定聊天室发送消息byte[] data = Encoding.ASCII.GetBytes($"SendMessageToChatRoomIP2|{chatRoomId}|client2m|{message}");await stream.WriteAsync(data, 0, data.Length);}

4.接收消息

private async Task ReceiveMessages(){byte[] buffer = new byte[1024];int bytesRead;while (connected){try{bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);string message = Encoding.ASCII.GetString(buffer, 0, bytesRead);DisplayMessage(message);}catch (Exception ex){textBoxReceivedMessages.AppendText($"Error receiving message: {ex.Message}" + Environment.NewLine);}}}private void DisplayMessage(string message){if (InvokeRequired){Invoke(new Action<string>(DisplayMessage), message);return;}textBoxReceivedMessages.AppendText(message + Environment.NewLine);}

5.点击事件

Send

   private async void buttonSend_Click(object sender, EventArgs e){if (!connected){textBoxReceivedMessages.AppendText("Not connected to server." + Environment.NewLine);return;}string message = textBoxSendMessage.Text;if (!string.IsNullOrEmpty(message)){// 发送消息给中转端 C1,请求向聊天室发送消息await SendMessageToChatRoom("room001", message);textBoxSendMessage.Clear();textBoxReceivedMessages.AppendText("Sent message to chat room: room001"  + Environment.NewLine);}else{textBoxReceivedMessages.AppendText("Please enter a message." + Environment.NewLine);}}

6.运行

服务端启动

Server listening on port 10086

服务端发收发消息到中转端

Sent message to chat room: room001
client2m  hihihi|socketclient 192.168.80.123  |::ffff:183.7.113.105|room001 
 

中转端拿到客户端信息->WebSocket端->中转端接收->客户端接收

Client joined chat room room001
Received message from WSSserver_sr : client2m: hihihi|socketclient 192.168.80.123 |socketserver:::ffff:183.7.113.105|room001

客户端也可以用IOS SOCKET5发送消息

//...         dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{NSData * sendData = [@"JoinChatRoom|room001" dataUsingEncoding:NSUTF8StringEncoding];[self.socket writeData:sendData withTimeout:-1 tag:1];dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{NSData * sendData = [@"SendMessageToChatRoomIP2|room001|userid001|hello" dataUsingEncoding:NSUTF8StringEncoding];[self.socket writeData:sendData withTimeout:-1 tag:2];[self.socket readDataWithTimeout:-1 tag:1];});});//...

Run


http://www.ppmy.cn/news/1434563.html

相关文章

Pytorch或Tensorflow 深度学习库安装 (简易版)

Tensorflow 2.X安装 0、 pytorch 支持 conda虚拟环境 cuda 和 cudnn1、创建conda环境2、测试GPU是否可用3、在机器上安装cuda 和 cudnnCUDA 安装cudnn 安装 0、 pytorch 支持 conda虚拟环境 cuda 和 cudnn 如果只用pytorch&#xff0c; 只需在虚拟环境安装cuda 和 cudnn即可&am…

JavaScript 模块导出示例

JavaScript 模块导出示例说明 在 JavaScript 中&#xff0c;我们可以通过 export 关键字将模块中的功能导出&#xff0c;以供其他模块使用。导出可以是单个默认值&#xff0c;也可以是多个命名值。本文将分别介绍导出单个值和导出多个值的示例说明。 导出单个值 当模块中只有…

MySQL你想知道序列当前生成的值,你可以使用SHOW TABLE STATUS命令或者查询information_schema数据库

在MySQL中&#xff0c;如果你想知道序列当前生成的值&#xff08;例如&#xff0c;自增主键的当前值&#xff09;&#xff0c;你可以使用SHOW TABLE STATUS命令或者查询information_schema数据库。 使用SHOW TABLE STATUS命令&#xff1a; 这个命令可以显示关于表的各种信息&…

AI助力科研创新与效率双提升:ChatGPT深度科研应用、数据分析及机器学习、AI绘图与高效论文撰写

2022年11月30日&#xff0c;可能将成为一个改变人类历史的日子——美国人工智能开发机构OpenAI推出了聊天机器人ChatGPT3.5&#xff0c;将人工智能的发展推向了一个新的高度。2023年4月&#xff0c;更强版本的ChatGPT4.0上线&#xff0c;文本、语音、图像等多模态交互方式使其在…

MySQL数据库精讲001——概述

MySQL数据库精讲001——概述 文章目录 MySQL数据库精讲001——概述1.1 安装1.1.1 版本1.1.2 安装一、下载二、解压三、配置1. 添加环境变量2. 初始化MySQL3. 注册MySQL服务4. 启动MySQL服务5. 修改默认账户密码 四、登录MySQL五、卸载MySQL 1.1.3 连接1.1.4 企业使用方式(了解)…

Tomcat服务器的优化经验

对于优化Tomcat服务器的经验&#xff0c;以下是一些常见的做法和建议&#xff1a; **调整内存配置&#xff1a;**Tomcat服务器的性能很大程度上取决于内存的配置。确保为Tomcat分配足够的堆内存和非堆内存&#xff0c;以避免OutOfMemoryError等内存相关的问题。可以通过编辑Tom…

实验4 数字频率计

实验目的&#xff1a; 1、使用铆孔U7输出一个脉冲&#xff0c;频率不定。 2、使用铆孔V7测量脉冲频率&#xff0c;并在数码管上显示。 实验内容及步骤&#xff1a; 设计原理 测量频率的方法有很多&#xff0c;按照其工作原理分为无源测量法、比较法、示波器法和计数法等。…

HOT100与剑指Offer

文章目录 前言一、70. 爬楼梯&#xff08;HOT100&#xff09;二、118. 杨辉三角&#xff08;HOT100&#xff09;总结 前言 一个本硕双非的小菜鸡&#xff0c;备战24年秋招&#xff0c;计划刷完hot100和剑指Offer的刷题计划&#xff0c;加油&#xff01; 根据要求&#xff0c;每…