- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我的 TCP ping/pong 工作正常,但在尝试添加第二种数据类型后,我遇到了接收程序从未触发 BeginReceive
回调的情况。
代码是相同的,除了第二个(有问题的)数据类型,序列化是提前完成的。这让我相信问题可能在于 BeginSend
被第二种数据类型调用得更快,可能在 BeginReceive
在另一个程序中被调用之前。
或者,我想知道数据大小是否存在差异。
所以我对 SO 的问题是:是否有可能问题是先发送再接收?如果是这样,一个人如何处理呢?如果不是,还有什么地方出了问题?
enum DataType : byte { A, B }
TcpListener _listener = new TcpListener(IPAddress.Any, 2323);
DataType _expectedDataType;
Constructor() { _listener.Start(); }
Connect() { _listener.BeginAcceptSocket(OnConnect, null); }
OnConnect(IAsyncResult result)
{
_socket = _listener.EndAcceptSocket(result);
_socket.ReceiveTimeout = 1000;
_socket.SendTimeout = 1000;
_expectedDataType = DataType.A;
if (_socket.Connected)
ReceiveData();
else
Connect();
}
ReceiveData()
{
Debug.Log("Receiving " + _expectedDataType + " Data");
// EDIT: The problem lied in the fact that the length parameter is sometimes longer than the first length parameter that was ever used
_socket.BeginReceive(_dataBuffer[(int)_expectedDataType], 0, _dataBuffer[_expectedDataType].Length, SocketFlags.None, OnReceiveData, null);
// buffer array is 119 for A, 133 for B
}
OnReceiveData(IAsyncResult result)
{
var bytes = _socket.EndReceive(result);
Debug.Log("Received " + bytes + "bytes of " + _expectedDataType + " Data");
// ... Deserialize several variables from the buffer based on data type ...
if (_needToUpdateBData)
_expectedDataType = DataType.B;
else
_expectedDataType = DataType.A
_socket.BeginSend(new[]{(byte)_expectedDataType}, 0, 1, SocketFlags.None, OnSendRequest, null);
}
OnSendRequest(IAsyncResult result)
{
var bytes = _socket.EndSend(result);
Debug.Log("Sent " + _expectedDataType + " Request " + bytes + "bytes");
ReceiveData();
}
TcpClient _client = new TcpClient();
DataType _expectedDataType;
OnEnterIpAddress(string ipAddress) { _client.BeginConnect(IPAddress.Parse(ipAddress), 2323, OnClientConnect, null); }
OnClientConnect(IAsyncResult result)
{
_client.EndConnect(result);
_stream = _client.GetStream();
_expectedDataType = DataType.A;
SendData();
}
SendData()
{
// ... Serialize into buffer based on expectedDataType
// This is where A takes a long time, and B is nearly instant ...
var bytes = _buffer[(int)_expectedDataType].Length;
Debug.Log("Sending " + _expectedDataType + " data with length of " + bytes + "bytes");
_stream.BeginWrite(_buffer[(int)_expectedDataType], 0, bytes, OnWrite, null);
}
OnWrite(IAsyncCallback)
{
_stream.EndWrite(result);
Debug.Log("Sent " + _expectedDataType + " data, awaiting response");
_stream.BeginRead(_response, 0, 1, OnRead, null);
}
OnRead(IAsyncCallback)
{
var bytes = _stream.EndRead(result);
Debug.Log("Received " + bytes + "bytes of " + _expectedDataType + " data");
_expectedDataType = (DataType)_response[0];
SendData();
}
如果我禁用 _needToUpdateBData
,那么只有 A
数据被发送,这两个部分会顺畅地来回切换。如果 _needToUpdateBData
设置为 true,发送方将卡在“已发送 B 数据,等待响应”,接收方将卡在“接收 B 数据”,即 OnReciveData
永远不会触发回调。
即使将 Socket.ReceiveTimeout 设置为 1000ms,它仍然无限期地卡在“接收 B 数据”上。
请注意,缺少 try/catches 是因为我打算在使用重新连接逻辑使事情复杂化之前来回运行它(实际上,已删除几个以使这篇文章更加简洁)。
最佳答案
Is it possible that send before receive is the problem?
不,TCP 连接的一侧永远无法确定另一侧是否有未决读取。即使远程端想要发出读取,其线程也可能会被取消调度很长时间。 TCP 必须能够在没有这种保证的情况下工作。这不可能是一个问题。
var bytes = _socket.EndReceive(result);
Debug.Log("Received " + bytes + "bytes of " + _expectedDataType + " Data");
// ... Deserialize several variables from the buffer based on data type ...
这看起来像是您假设单个读取调用将返回您想要的所有数据的经典错误。相反,它可以返回部分结果。您不可能通过单个读取调用反序列化,所以我认为这是这个经典错误的一个例子。
超时不适用于异步 IO(我不知道为什么,这太糟糕了)。也许,无论如何你都不应该使用异步 IO。我可以说是因为您异步接受套接字纯粹是在浪费开发时间。这让我认为您没有有意识地在同步 IO 和异步 IO 之间做出决定。
if (_socket.Connected)
连接后怎么会是假的呢?没有意义。不要在不了解其作用的情况下从其他来源复制代码。这是一种常见的反模式。
套接字真的很难做好。最好的选择通常是使用现成的东西,例如 WCF、HTTP、websockets 等。
关于C# 套接字 : What if BeginSend is called before BeginReceive?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33987671/
我想了解以下方面的一些信息: Socket.BeginSend Method (array[]()[], Int32, Int32, SocketFlags, AsyncCallback, Objec
我需要将对套接字的 BeginSend 调用排队,并且我需要它们按时间顺序执行。为此,我使用信号量在回调函数可以运行时发出信号。 大多数情况下它是有效的,因为每个异步回调都在一个单独的线程上执行,但偶
我是编程新手,对异步套接字编程感到困惑。 例如,假设我有两个 BeginSend,一个接一个。第一个发送一百万个字符,第二个仅发送 64 个字符。 由于异步性质,第二个 BeginSend 不会在第一
所以我明白 Send 是同步的,而 BeginSend 是异步的。我听说套接字发送方法的数据传输速度比 BeginSend 快(注意:我不是在谈论 CPU 性能,而只是发送和接收数据包延迟)。谁能告诉
我正在编写一个套接字应用程序,它可以同时异步轮询多个服务器并向用户报告它们状态的任何变化。到目前为止,一切正常,除了一个我似乎无法弄清楚的小错误。 服务器每 10 秒创建一组套接字,然后调用异步连接。
我的 TCP ping/pong 工作正常,但在尝试添加第二种数据类型后,我遇到了接收程序从未触发 BeginReceive 回调的情况。 代码是相同的,除了第二个(有问题的)数据类型,序列化是提前完
当我向远程 机器发送大量数据时,发送回调几乎立即执行。 [05:10:35:981] ChildSocket.Send(): Sending 1048508 bytes. [05:10:35:988]
这是一个我不太明白的异步套接字场景...我有 2 个 Tcp 套接字,一个客户端套接字和一个服务器套接字。我的服务器套接字已绑定(bind)并正在监听端口。 我的客户端套接字连接到服务器套接字(使用
比如说,我有一个类,它包装了一个 Socket 并且(除其他外)执行异步数据发送。 我按以下方式执行发送(大大简化 - 无错误处理等): private Socket _socket; public
我使用以下代码异步发送数据,但我注意到在从 asyncRes 获取的 AsyncWaitHandle 中使用 WaitOne 根本不等待。我检查了 MSDN,它说我应该使用 ManualResetEv
.NET 中的 Socket 类公开了以下方法: Socket.BeginSend Method (IList>, SocketFlags, AsyncCallback, Object) 我有一个返回
这里的工作代码 static MessageSender TopicClient; public static void SendTopicMessage(BrokeredMessage messag
这里的工作代码 static MessageSender TopicClient; public static void SendTopicMessage(BrokeredMessage messag
例。 http://msdn.microsoft.com/en-us/library/bew39x2a%28v=vs.110%29.aspx我想知道像 BeginSend、BeginReceive 等
我是一名优秀的程序员,十分优秀!