当前位置: 首页 > news >正文

socket 客户端和服务器通信

服务器

using BarrageGrab;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;namespace Lyx {class Server{private TcpListener listener;private ConcurrentDictionary<TcpClient, DateTime> clients = new ConcurrentDictionary<TcpClient, DateTime>();private CancellationTokenSource cts = new CancellationTokenSource();public void Start(int port){listener = new TcpListener(IPAddress.Any, port);listener.Start();Console.WriteLine($"服务器已启动,监听端口 {port}...");new Thread(AcceptClients) { IsBackground = true }.Start();new Thread(CheckHeartbeats) { IsBackground = true }.Start();new Thread(HandleConsoleInput) { IsBackground = true }.Start();}private void AcceptClients(){try{while (!cts.Token.IsCancellationRequested){TcpClient client = listener.AcceptTcpClient();Console.WriteLine("新客户端连接:" + client.Client.RemoteEndPoint);clients.TryAdd(client, DateTime.Now);new Thread(() => HandleClient(client)) { IsBackground = true }.Start();}}catch (SocketException) { } // 监听器被停止时正常退出}private void HandleClient(TcpClient client){NetworkStream stream = null;try{stream = client.GetStream();byte[] buffer = new byte[1024];while (!cts.Token.IsCancellationRequested){int bytesRead;lock (client) // 同步网络流访问{if (!stream.DataAvailable){Thread.Sleep(100);continue;}bytesRead = stream.Read(buffer, 0, buffer.Length);}if (bytesRead <= 0) break;string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);Console.WriteLine($"收到消息: {message}");if (message == "heartbeat"){clients.AddOrUpdate(client, DateTime.Now, (_, __) => DateTime.Now);SendMessage(client, "heartbeat");Logger.PrintColor($"服务器发送心跳: {message} ,给客户端成功:{client.Client.RemoteEndPoint}", ConsoleColor.Yellow);continue;}//SendMessage(client, "服务器收到: " + message);}}catch (Exception ex) { Console.WriteLine($"客户端错误: {ex.Message}"); }finally{if (client.Connected ){Console.WriteLine("客户端断开:" + client.Client.RemoteEndPoint);clients.TryRemove(client, out _);client.Close();stream?.Close();}}}public void BroadcastMessage(string message){byte[] data = Encoding.UTF8.GetBytes("服务器广播: " + message);foreach (var client in clients.Keys.ToArray()){try{lock (client){client.GetStream().Write(data, 0, data.Length);}}catch { }}Console.WriteLine("广播消息已发送");}public void SendMessage(TcpClient client, string message){if (!clients.ContainsKey(client)) return;byte[] data = Encoding.UTF8.GetBytes(message);try{lock (client) // 同步网络流访问{client.GetStream().Write(data, 0, data.Length);}Console.WriteLine($"消息发送成功 -> {client.Client.RemoteEndPoint}: {message}");}catch{Console.WriteLine("消息发送失败");}}private void HandleConsoleInput(){while (!cts.Token.IsCancellationRequested){string input = Console.ReadLine();if (input?.ToLower() == "exit"){Stop();break;}else if (!string.IsNullOrWhiteSpace(input)){BroadcastMessage(input);}}}private void CheckHeartbeats(){while (!cts.Token.IsCancellationRequested){Thread.Sleep(5000);DateTime now = DateTime.Now;foreach (var client in clients.Keys.ToArray()){if (clients.TryGetValue(client, out DateTime last) &&(now - last).TotalSeconds > 10){Console.WriteLine("客户端超时断开:" + client.Client.RemoteEndPoint);clients.TryRemove(client, out _);client.Close();}}}}public void Stop(){cts.Cancel();listener.Stop();foreach (var client in clients.Keys.ToArray()){client.Close();clients.TryRemove(client, out _);}Console.WriteLine("服务器已停止");}public  void Main(){Server server = new Server();server.Start(54621);}}}

客户端

using System;
using System.Collections;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;public class SocketClient : MonoBehaviour
{private TcpClient client;private NetworkStream stream;private Thread receiveThread;private bool isConnected = false;private string serverIP = "127.0.0.1"; // 服务器IP地址private int serverPort = 54621; // 服务器端口private float heartbeatTimeout = 5f; // 心跳超时时间private float heartbeatInterval = 0.5f; // 心跳发送间隔时间private float lastHeartbeatTime;private float lastSendHeartbeatTime;private bool updateHeartbeat = false; // 标志位,用于通知主线程更新心跳时间private int reconnectAttempts = 0; // 重连尝试次数private const int maxReconnectAttempts = 3; // 最大重连次数private const float reconnectInterval = 2f; // 重连间隔时间void Start(){ConnectToServer();}void Update(){// 检查是否需要更新心跳时间if (updateHeartbeat){lastHeartbeatTime = Time.time;updateHeartbeat = false;}// 检查心跳超时if (isConnected && Time.time - lastHeartbeatTime > heartbeatTimeout){Debug.Log("Heartbeat timeout, disconnecting...");Disconnect();}// 定时发送心跳消息if (isConnected && Time.time - lastSendHeartbeatTime > heartbeatInterval){SendData("heartbeat");lastSendHeartbeatTime = Time.time;}}void ConnectToServer(){try{client = new TcpClient(serverIP, serverPort);stream = client.GetStream();isConnected = true;lastHeartbeatTime = Time.time;lastSendHeartbeatTime = Time.time;reconnectAttempts = 0; // 重置重连尝试次数receiveThread = new Thread(new ThreadStart(ReceiveData));receiveThread.IsBackground = true;receiveThread.Start();Debug.Log("Connected to server.");}catch (Exception e){Debug.LogError("Error connecting to server: " + e.Message);TryReconnect();}}void ReceiveData(){byte[] buffer = new byte[1024];while (isConnected){try{int bytesRead = stream.Read(buffer, 0, buffer.Length);if (bytesRead > 0){string receivedMessage = Encoding.UTF8.GetString(buffer, 0, bytesRead);if (receivedMessage != null){Debug.Log("Received from server: " + receivedMessage);// 如果是心跳响应,通知主线程更新心跳时间if (receivedMessage.Equals("heartbeat")){updateHeartbeat = true;}}}}catch (Exception e){Debug.LogError("Error receiving data: " + e.Message);Disconnect();break;}}}public void SendData(string message){if (isConnected){try{byte[] data = Encoding.UTF8.GetBytes(message);stream.Write(data, 0, data.Length);Debug.Log("Sent to server: " + message);}catch (Exception e){Debug.LogError("Error sending data: " + e.Message);Disconnect();}}}void Disconnect(){if (isConnected){isConnected = false;if (receiveThread != null && receiveThread.IsAlive)receiveThread.Abort();if (stream != null)stream.Close();if (client != null)client.Close();Debug.Log("Disconnected from server.");// 尝试重连TryReconnect();}}void TryReconnect(){Debug.Log("触发重连机制");if (reconnectAttempts < maxReconnectAttempts){reconnectAttempts++;Debug.Log($"Attempting to reconnect ({reconnectAttempts}/{maxReconnectAttempts})...");Invoke("ConnectToServer", reconnectInterval); // 2秒后重连}else{Debug.Log("Max reconnection attempts reached. Giving up.");}}void OnDestroy(){Disconnect();}
}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.dtcms.com/a/136339.html

相关文章:

  • 《AI大模型应知应会100篇》第21篇:Prompt设计原则:让大模型精准理解你的需求
  • 本地搭建全网可访问的开源音乐服务器Melody结合内网穿透随时听歌
  • 数据结构-数组与广义表
  • 股指期货怎么锁定利润?
  • Gobuster :dir、dns、vhost
  • 【C++】 —— 笔试刷题day_17
  • PCIE网卡驱动DMA初始化配置
  • 编程技能:调试02,设置断点与删除断点
  • macOS安装java
  • 跨平台开发选Java还是C?应用场景与性能深度对比
  • 【WPF】 在WebView2使用echart显示数据
  • 深度学习--前向传播,反向传播和计算图
  • leetcode 122. Best Time to Buy and Sell Stock II
  • wait()和sleep()
  • PCIE Link Equalizaton
  • Java基础 - 集合框架总结与实战指南
  • Gin趣讲
  • 精益数据分析(3/126):用数据驱动企业发展的深度解析
  • Arcgis经纬线标注设置(英文、刻度显示)
  • Android主流播放器功能详解
  • 16.使用豆包将docker-compose的yaml转为k8s的yaml,安装各种无状态服务
  • uniapp-商城-26-vuex 使用流程
  • Java c线程等待ab线程执行完再执行
  • 关于DApp、DeFi、IDO私募及去中心化应用开发的综合解析
  • 4.15redis点评项目下
  • 3款本周高潜力开源AI工具(多模态集成_隐私本地化)
  • 暂存一下等会写
  • 选择排序(简单选择排序、堆排序)
  • 【探商宝】跨境关税博弈下的技术破局:从头部平台现象看数字贸易体系重构
  • 【FFmpeg从入门到精通】第一章-FFmpeg简介