为何TcpClient代码在VB.NET中正常运行,在C#中却异常?
问题拆解与排查结果
我来帮你理清楚这段TcpClient代码从VB.NET转C#时遇到的问题,以及最终的根因:
背景
接手需要重构的代码时,发现VB.NET版本的TcpClient逻辑能正常运行,但转成C#后出现了连续的问题,一开始我怀疑是两种语言中Byte数组构造的差异导致的,已知BUFFER_SIZE值为2048。
VB.NET 可正常运行的代码
Dim bytesRcvd As Integer = 0 Dim byteSendBuffer As Byte() = New Byte(BUFFER_SIZE - 1) {} Dim byteReceiveBuffer As Byte() = New Byte(BUFFER_SIZE - 1) {} Dim receiveMessage As String = Nothing byteSendBuffer = Encoding.ASCII.GetBytes(sendMessage) Dim client As System.Net.Sockets.TcpClient = Nothing Dim netStream As System.Net.Sockets.NetworkStream = Nothing client = New System.Net.Sockets.TcpClient("localhost", 9060) netStream = client.GetStream() netStream.Write(byteSendBuffer, 0, byteSendBuffer.Length) bytesRcvd = netStream.Read(byteReceiveBuffer, 0, BUFFER_SIZE) receiveMessage = Encoding.ASCII.GetString(byteReceiveBuffer, 0, bytesRcvd) netStream.Close() client.Close()
初始转换的C# 代码(存在问题)
int bytesRcvd = 0; var byteSendBuffer = new Byte[BUFFER_SIZE - 1]; var byteReceiveBuffer = new Byte[BUFFER_SIZE - 1]; string receiveMessage = null; byteSendBuffer = Encoding.ASCII.GetBytes(sendMessage); System.Net.Sockets.TcpClient client = null; System.Net.Sockets.NetworkStream netStream = null; client = new System.Net.Sockets.TcpClient("localhost", 9060); netStream = client.GetStream(); netStream.Write(byteSendBuffer, 0, byteSendBuffer.Length); bytesRcvd = netStream.Read(byteReceiveBuffer, 0, BUFFER_SIZE); receiveMessage = Encoding.ASCII.GetString(byteReceiveBuffer, 0, bytesRcvd); netStream.Close(); client.Close();
问题现象与分析
第一个错误:参数越界异常
运行C#代码时,netStream.Read处报错:"Specified argument was out of the range of valid values."
这是VB.NET和C#数组初始化的核心差异导致的:- VB.NET中
New Byte(BUFFER_SIZE - 1)创建的是长度为BUFFER_SIZE的数组(括号内是数组的最大索引值) - 而C#中
new Byte[BUFFER_SIZE - 1]创建的是长度为BUFFER_SIZE - 1的数组(方括号内是数组的实际长度)
当调用netStream.Read(byteReceiveBuffer, 0, BUFFER_SIZE)时,要求读取最多BUFFER_SIZE个字节,但数组仅能容纳BUFFER_SIZE-1个字节,直接触发了参数越界。
- VB.NET中
第二个问题:Read方法无限挂起
修改C#的Byte数组定义为new Byte[BUFFER_SIZE]后,参数越界的错误消失了,但netStream.Read会无限挂起,哪怕用netStream.CanRead判断也没用。
这是因为NetworkStream.Read是阻塞式方法——它会一直等待,直到有数据可读或者连接被关闭。CanRead属性仅表示当前流是否处于可读状态,并不代表已有数据到达。
最终根因排查
后来我新增VB项目做对比测试,发现并非C#代码本身的问题——最终排查出,问题出在远端的监听服务:当前程序没有权限访问该服务,导致服务端返回消息异常,最终服务端根本没有响应任何数据,所以Read方法会一直阻塞等待,直到超时。
内容的提问来源于stack exchange,提问作者user1447679
相关产品推荐
相关产品推荐

