因此,似乎阻塞的Read()可以在接收到发送给它的所有数据之前返回.反过来,我们用一个循环来包装Read(),该循环由相关流中的DataAvailable值控制.问题是你可以在这个while循环中接收更多数据,但是没有幕后处理让系统知道这一点.我在网上找到的大多数解决方案都不适用于我.
我最后做的是作为循环的最后一步,在从流中读取每个块之后,我做了一个简单的Thread.Sleep(1).这似乎给系统提供了更新的时间,而且我没有得到准确的结果,但这对于解决方案来说似乎有点苛刻且有点"间接".
下面是我正在处理的情况列表:IIS应用程序和独立应用程序之间的单个TCP连接,都是用C#编写的,用于发送/接收通信.它发送请求然后等待响应.此请求由HTTP请求启动,但我没有从HTTP请求中读取数据这个问题,事后是这样.
以下是处理传入连接的基本代码
protected void OnClientCommunication(TcpClient oClient)
{
NetworkStream stream = oClient.GetStream();
MemoryStream msIn = new MemoryStream();
byte[] aMessage = new byte[4096];
int iBytesRead = 0;
while ( stream.DataAvailable )
{
int iRead = stream.Read(aMessage, 0, aMessage.Length);
iBytesRead += iRead;
msIn.Write(aMessage, 0, iRead);
Thread.Sleep(1);
}
MemoryStream msOut = new MemoryStream();
// .. Do some processing adding data to the msOut stream
msOut.WriteTo(stream);
stream.Flush();
oClient.Close();
}
Run Code Online (Sandbox Code Playgroud)
所有反馈都欢迎提供更好的解决方案,或者只是赞一下需要给Sleep(1)一个允许在检查DataAvailable值之前正确更新的东西.
猜猜我希望2年后这个问题的答案不是如何仍然是:)
我正在编写一些机器学习软件用于公平,并希望找到一些刻度数据或至少3或5分钟的数据.
我想有一到两年的时间进行测试.
我并不真正关心数据的交换,只要它来自某个主要交易所.
还有哪里可以连接到延迟'实时'数据的数据流?
数据不一定是免费的,但免费更好:-)
我有一个应用程序,它同时生成几百个TCP连接,并从它们接收一个恒定的数据流.
private void startReceive()
{
SocketAsyncEventArgs e = new SocketAsyncEventArgs();
e.Completed += receiveCompleted;
e.SetBuffer(new byte[1024], 0, 1024);
if (!Socket.ReceiveAsync(e)) { receiveCompleted(this, e); }
}
void receiveCompleted(object sender, SocketAsyncEventArgs e)
{
ProcessData(e);
if (!Socket.ReceiveAsync(e)) { receiveCompleted(this, e); }
}
Run Code Online (Sandbox Code Playgroud)
我的尝试导致了这样的事情:
private async void StartReceive()
{
byte[] Buff = new byte[1024];
int recv = 0;
while (Socket.Connected)
{
recv = await NetworkStream.ReadAsync(Buff, 0, 1024);
ProcessData(Buff,recv);
}
}
Run Code Online (Sandbox Code Playgroud)
我遇到的问题是方法调用StartReceive()会阻塞,而不是到达随附的StartSend() method called afterStartReceive(). Creating a new task forStartReceive() …
这个让我困惑.当我甚至没有打电话时,我收到关于寻找的错误?
我的代码看起来像这样:
// send 42
uint value = 42;
byte[] msg = BitConverter.GetBytes(value);
stream.Write(msg, 0, sizeof(uint));
Run Code Online (Sandbox Code Playgroud)
我得到这个例外:
System.NotSupportedException was unhandled
Message="This stream does not support seek operations."
Source="System"
StackTrace:
at System.Net.Sockets.NetworkStream.Seek(Int64 offset, SeekOrigin origin)
at System.IO.BufferedStream.FlushRead()
at System.IO.BufferedStream.Write(Byte[] array, Int32 offset, Int32 count)
...
Run Code Online (Sandbox Code Playgroud)
流是类型System.IO.BufferedStream.可能会发生什么?
编辑更多信息:
sizeof(uint)==msg.length在这种情况下.
流声明为stream = new BufferedStream(new NetworkStream(socket), 1024)
编辑:
就是这样!虽然可以在一个单独读取和写入NetworkStream,但当切换到BufferedStream它时,必须有一个单独的读取和写入.显然,只需NetworkStream在同一个套接字上调用构造函数两次即可.
如果可以的话,我会接受Justin和Hans的答案,因为我让我完全理解错误,另一个让我找到解决方案.感谢大家!
我有一个项目,我正在尝试将序列化对象发送到服务器,然后等待"OK"或"ERROR"消息返回.
我似乎遇到了类似的问题:TcpClient发送/关闭问题
问题是,我似乎能够发送原始对象的唯一方法是关闭连接,但然后(当然)我迫不及待地想看看服务器是否成功处理了对象.
private void button4_Click(object sender, EventArgs e)
{
RequestPacket req = new RequestPacket();
/// ... Fill out request packet ...
/// Connect to the SERVER to send the message...
TcpClient Client = new TcpClient("localhost", 10287);
using (NetworkStream ns = Client.GetStream())
{
XmlSerializer xml = new XmlSerializer(typeof(RequestPacket));
xml.Serialize(ns, req);
/// NOTE: This doesn't seem to do anything....
/// The server doesn't get the object I just serialized.
/// However, if I use ns.Close() it does...
/// but then …Run Code Online (Sandbox Code Playgroud) 我想知道是否有人知道处理使用Socket对象和NetworkStream对象的类的最佳方法?有问题的类有一个NetworkStream实例和一个用于创建NetworkStream的Socket实例.
this.socket = new Socket(
AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp)
{
ReceiveBufferSize = 65536,
SendBufferSize = 150
};
this.socket.Connect(
new IPEndPoint(
IPAddress.Parse(
Properties.Settings.Default.MpsServer2),
Properties.Settings.Default.MpsPort2));
this.stream = new NetworkStream(
this.socket, true);
Run Code Online (Sandbox Code Playgroud)
在我的Dispose方法中,我应该这样做吗?
this.stream.Close();
this.socket.Shutdown(SocketShutdown.Both);
this.socket.Close();
Run Code Online (Sandbox Code Playgroud)
所有这些都是必要的还是过度杀伤?
我试图将一个古老的网络摄像头连接到我的计算机,我陷入了一个非常根本的问题 - 检测流的结束.
我正在使用TcpClient与相机通信,我实际上可以看到它传输命令数据,这里没有问题.
List<int> incoming = new List<int>();
TcpClient clientSocket = new TcpClient();
clientSocket.Connect(txtHost.Text, Int32.Parse(txtPort.Text));
NetworkStream serverStream = clientSocket.GetStream();
serverStream.Flush();
byte[] command = System.Text.Encoding.ASCII.GetBytes("i640*480M");
serverStream.Write(command, 0, command.Length);
Run Code Online (Sandbox Code Playgroud)
回读响应是问题的开始.我最初认为像下面的一些代码一样简单:
while (serverStream.DataAvailable)
{
incoming.Add(serverStream.ReadByte());
}
Run Code Online (Sandbox Code Playgroud)
但它没有,所以这次使用ReadByte()进行了另一个版本.描述说明:
从流中读取一个字节并将流中的位置前进一个字节,如果在流的末尾则返回-1.
所以我想我可以实现以下几点:
Boolean run = true;
int rec;
while (run)
{
rec = serverStream.ReadByte();
if (rec == -1)
{
run = false;
//b = (byte)'X';
}
else
{
incoming.Add(rec);
}
}
Run Code Online (Sandbox Code Playgroud)
不,仍然无法正常工作.我实际上可以看到数据进入和某个点之后(这并不总是相同的,否则我每次只能读取那么多字节)我开始得到0其余元素的值并且它不会停止直到我手动停止执行.这是它的样子:

所以我的问题是,我错过了一些基本的东西吗?如何检测流的结束?
非常感谢,
H.
MSDN文档似乎暗示NetworkStream.Read将始终立即返回.如果没有找到数据,则返回0.但是,我有一些当前部署的代码,仅在某些情况下(我还没有想出哪些代码),NetworkStream.Read似乎挂起.这是我能够从转储文件中收集的堆栈跟踪
00000000705ae850 000007fef784f60d DomainBoundILStubClass.IL_STUB(IntPtr, Byte*, Int32, System.Net.Sockets.SocketFlags) 00000000705ae930 000007fef785c930 System.Net.Sockets.Socket.Receive(Byte[], Int32, Int32, System.Net.Sockets.SocketFlags, System.Net.Sockets.SocketError ByRef) 00000000705ae9b0 000007ff004eb668 System.Net.Sockets.NetworkStream.Read(Byte[], Int32, Int32) 00000000705aea40 000007fef784e6ae MySocketStuff.SocketConnectCallback(System.IAsyncResult) 00000000705aeb20 000007fef84f2bbb System.Net.LazyAsyncResult.Complete(IntPtr) 00000000705aeb90 000007fef7853c7b System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) 00000000705aebe0 000007fef784e5d3 System.Net.ContextAwareResult.Complete(IntPtr) 00000000705aec40 000007fef7d027f9 System.Net.LazyAsyncResult.ProtectedInvokeCallback(System.Object, IntPtr) 00000000705aeca0 000007fef8b9815e System.Net.Sockets.Socket.ConnectCallback() 00000000705aed20 000007fef93e14c2 System.Threading._ThreadPoolWaitOrTimerCallback.PerformWaitOrTimerCallback(System.Object, Boolean)
我注意到NetworkStrea.Read实际上调用了Socket.Receive,据我所知,它可以阻塞.我只是不知道为什么有时它会阻止,有时它不会.
我试图了解NetworkStream.EndRead()的MSDN示例.有些部分我不明白.
所以这是示例(从MSDN复制):
// Example of EndRead, DataAvailable and BeginRead.
public static void myReadCallBack(IAsyncResult ar ){
NetworkStream myNetworkStream = (NetworkStream)ar.AsyncState;
byte[] myReadBuffer = new byte[1024];
String myCompleteMessage = "";
int numberOfBytesRead;
numberOfBytesRead = myNetworkStream.EndRead(ar);
myCompleteMessage =
String.Concat(myCompleteMessage, Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead));
// message received may be larger than buffer size so loop through until you have it all.
while(myNetworkStream.DataAvailable){
myNetworkStream.BeginRead(myReadBuffer, 0, myReadBuffer.Length,
new AsyncCallback(NetworkStream_ASync_Send_Receive.myReadCallBack),
myNetworkStream);
}
// Print out the received message to the console.
Console.WriteLine("You received the following message …Run Code Online (Sandbox Code Playgroud) 任何人都能指出这段代码中的缺陷吗?我正在使用TcpClient检索一些HTML.与IIS服务器通信时,NetworkStream.Read()似乎永远不会完成.如果我去使用Fiddler代理,它可以正常工作,但直接与目标服务器通信时,.read()循环将不会退出,直到连接异常时出现"远程服务器已关闭连接"之类的错误.
internal TcpClient Client { get; set; }
/// bunch of other code here...
try
{
NetworkStream ns = Client.GetStream();
StreamWriter sw = new StreamWriter(ns);
sw.Write(request);
sw.Flush();
byte[] buffer = new byte[1024];
int read=0;
try
{
while ((read = ns.Read(buffer, 0, buffer.Length)) > 0)
{
response.AppendFormat("{0}", Encoding.ASCII.GetString(buffer, 0, read));
}
}
catch //(SocketException se)
{
}
finally
{
Close();
}
Run Code Online (Sandbox Code Playgroud)
更新
在调试器中,我可以看到整个响应立即通过并附加到我的StringBuilder(响应).当服务器完成发送响应或我的代码没有检测到它时,似乎连接没有被关闭.
结论 正如这里所说的,最好利用协议的产品(在HTTP的情况下,Content-Length头)来确定事务何时完成.但是,我发现并非所有页面都设置了内容长度.所以,我现在正在使用混合解决方案:
对于所有事务,请将请求的Connection标头设置为"关闭",以防止服务器保持套接字打开.这可以提高服务器在响应您的请求时关闭连接的几率.
如果Content-Length已设置,请使用它来确定请求何时完成.
否则,将NetworkStream的RequestTimeout属性设置为一个大但合理的值,如1秒.然后,循环开启,NetworkStream.Read()直到a)超时发生,或b)您读取的字节数比您要求的少.
感谢大家的出色和详细的回复.
networkstream ×10
c# ×9
sockets ×5
tcpclient ×5
asynchronous ×2
asp.net ×1
async-await ×1
blocking ×1
finance ×1
stream ×1
tcp ×1