通过Socket发送高频数据流最优方案?C#客户端对接Java服务端问题咨询
问题根因
- 服务端使用
BufferedReader.readLine()读取数据,该方法只有接收到换行符\n、\r\n或者输入流关闭时才会返回结果。你之前每次发送完关闭Socket,相当于主动结束输入流,所以服务端可以正常读到数据;复用Socket不关闭时,因为发送的内容没有换行符,readLine()会一直阻塞等待,就表现为读不到数据。 - 每次Update都新建、连接、关闭Socket的方案会频繁触发TCP三次握手、四次挥手流程,大量浪费系统资源,吞吐和延迟表现都很差,完全不适合高频数据发送场景。
修复方案
1. C#客户端修改
将Socket初始化、连接逻辑移到Update外仅执行一次,每次发送数据时末尾追加换行符,程序退出时再关闭Socket即可。
修改后代码示例:
// 把Socket定义为类成员变量,初始化和连接只执行一次 private Socket _soc; // 初始化方法(比如Start/Init里执行一次) void Init() { _soc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); string server = "127.0.0.1"; IPAddress ipAdd = IPAddress.Parse(server); IPEndPoint remoteEP = new IPEndPoint(ipAdd, 3456); _soc.Connect(remoteEP); } void Update() { float speed = telemetria.vehicle.data.Get(Channel.Vehicle, VehicleData.Speed)*3.6f/1000.0f; // 注意末尾加换行符,匹配服务端readLine的读取规则 byte[] msg = System.Text.Encoding.ASCII.GetBytes($"velocidad(k/h): {speed}\n"); _soc.Send(msg); } // 程序退出时调用关闭 void OnDestroy() { if(_soc != null && _soc.Connected) { _soc.Close(); _soc.Dispose(); } }
2. Java服务端修改
原来的逻辑每次接收到连接只读一行就丢弃,适配长连接需要在同一个Socket连接内循环读取数据:
public static void main(String[] args) throws IOException{ ServerSocket ss = new ServerSocket(3456); while(true) { Socket s = ss.accept(); // 每个连接开单独线程处理,避免阻塞后续连接 new Thread(() -> { try { InputStreamReader in = new InputStreamReader(s.getInputStream()); BufferedReader bf = new BufferedReader(in); String str; // 循环读取同一个连接的多行数据 while ((str = bf.readLine()) != null) { System.out.println(str); } } catch (IOException e) { e.printStackTrace(); } finally { try { s.close(); } catch (IOException e) { e.printStackTrace(); } } }).start(); } }
内容的提问来源于stack exchange,提问作者Franco Arellano
相关产品推荐
相关产品推荐

