- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试实现包装器类,它将简单地连接到 TCP 服务器并等待数据。一旦数据从服务器提交 - 我将收到此数据并将其传递给我类(class)的订阅者。
这一切都有效。现在我想添加外部功能以在计时器上“重置”此类(每隔一段时间强制重新连接)以保持连接有效。我的想法是,可以根据需要多次调用 Init
方法来重置套接字。但是,我确实遇到了各种异常(exception)情况。
类代码:
namespace Ditat.GateControl.Service.InputListener
{
using System;
using System.ComponentModel;
using System.Net;
using System.Net.Sockets;
using System.Text;
public class BaseTCPSocketListener : IInputListener
{
#region Events/Properties
public event EventHandler<Exception> OnError;
public event EventHandler<string> OnDataReceived;
private string host;
private int port;
private int delayToClearBufferSeconds = 5;
private TcpClient client;
private readonly byte[] buffer = new byte[1024];
/// <summary>
/// Will accumulate data as it's received
/// </summary>
private string DataBuffer { get; set; }
/// <summary>
/// Store time of last data receipt. Need this in order to purge data after delay
/// </summary>
private DateTime LastDataReceivedOn { get; set; }
#endregion
public BaseTCPSocketListener()
{
// Preset all entries
this.LastDataReceivedOn = DateTime.UtcNow;
this.DataBuffer = string.Empty;
}
public void Init(string config)
{
// Parse info
var bits = config.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
this.host = bits[0];
var hostBytes = this.host.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
var hostIp = new IPAddress(new[] { byte.Parse(hostBytes[0]), byte.Parse(hostBytes[1]), byte.Parse(hostBytes[2]), byte.Parse(hostBytes[3]) });
this.port = int.Parse(bits[1]);
this.delayToClearBufferSeconds = int.Parse(bits[2]);
// Close open client
if (this.client?.Client != null)
{
this.client.Client.Disconnect(true);
this.client = null;
}
// Connect to client
this.client = new TcpClient();
if (!this.client.ConnectAsync(hostIp, this.port).Wait(2500))
throw new Exception($"Failed to connect to {this.host}:{this.port} in allotted time");
this.EstablishReceiver();
}
protected void DataReceived(IAsyncResult result)
{
// End the data receiving that the socket has done and get the number of bytes read.
var bytesCount = 0;
try
{
bytesCount = this.client.Client.EndReceive(result);
}
catch (Exception ex)
{
this.RaiseOnErrorToClient(new Exception(nameof(this.DataReceived)));
this.RaiseOnErrorToClient(ex);
}
// No data received, establish receiver and return
if (bytesCount == 0)
{
this.EstablishReceiver();
return;
}
// Convert the data we have to a string.
this.DataBuffer += Encoding.UTF8.GetString(this.buffer, 0, bytesCount);
// Record last time data received
this.LastDataReceivedOn = DateTime.UtcNow;
this.RaiseOnDataReceivedToClient(this.DataBuffer);
this.DataBuffer = string.Empty;
this.EstablishReceiver();
}
private void EstablishReceiver()
{
try
{
// Set up again to get the next chunk of data.
this.client.Client.BeginReceive(this.buffer, 0, this.buffer.Length, SocketFlags.None, this.DataReceived, this.buffer);
}
catch (Exception ex)
{
this.RaiseOnErrorToClient(new Exception(nameof(this.EstablishReceiver)));
this.RaiseOnErrorToClient(ex);
}
}
private void RaiseOnErrorToClient(Exception ex)
{
if (this.OnError == null) return;
foreach (Delegate d in this.OnError.GetInvocationList())
{
var syncer = d.Target as ISynchronizeInvoke;
if (syncer == null)
{
d.DynamicInvoke(this, ex);
}
else
{
syncer.BeginInvoke(d, new object[] { this, ex });
}
}
}
private void RaiseOnDataReceivedToClient(string data)
{
if (this.OnDataReceived == null) return;
foreach (Delegate d in this.OnDataReceived.GetInvocationList())
{
var syncer = d.Target as ISynchronizeInvoke;
if (syncer == null)
{
d.DynamicInvoke(this, data);
}
else
{
syncer.BeginInvoke(d, new object[] { this, data });
}
}
}
}
}
客户端代码(在按钮下点击表单)
private void ListenBaseButton_Click(object sender, EventArgs e)
{
if (this.bsl == null)
{
this.bsl = new BaseTCPSocketListener();
this.bsl.OnDataReceived += delegate (object o, string s)
{
this.DataTextBox.Text += $"Base: {DateTime.Now} - {s}" + Environment.NewLine;
};
this.bsl.OnError += delegate (object o, Exception x)
{
this.DataTextBox.Text += $"Base TCP receiver error: {DateTime.Now} - {x.Message}" + Environment.NewLine;
};
}
try
{
this.bsl.Init("192.168.33.70|10001|10");
this.DataTextBox.Text += "BEGIN RECEIVING BSL data --------------------------" + Environment.NewLine;
}
catch (Exception exception)
{
this.DataTextBox.Text += $"ERROR CONNECTING TO BSL ------------{exception.Message}" + Environment.NewLine;
}
}
我得到的异常。在 DataReceived
The IAsyncResult object was not returned from the corresponding asynchronous method on this class.
在点击之后,我从 EstablishReceiver
中的处理程序中得到异常
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
如何正确确保套接字关闭和重新打开?
最佳答案
The IAsyncResult object was not returned from the corresponding asynchronous method on this class.
这是一个众所周知的问题,发生在为先前的套接字调用数据回调 (DataReceived()
) 时。在这种情况下,您将使用不正确的 IAsyncResult
实例调用 Socket.EndReceive()
,这会引发上述异常。
Asynchronous Client Socket Example包含此问题的可能解决方法:将调用 BeginReceive()
的套接字存储在状态对象中,然后将其传递给 DataReceived
回调:
StateObject 类
public class StateObject
{
public Socket Socket { get; set; }
public byte[] Buffer { get; } = new byte[1024];
public StateObject(Socket socket)
{
Socket = socket;
}
}
EstablishReceiver() 方法:
private void EstablishReceiver()
{
try
{
var state = new StateObject(client.Client);
// Set up again to get the next chunk of data.
this.client.Client.BeginReceive(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, this.DataReceived, state);
}
catch (Exception ex)
{
this.RaiseOnErrorToClient(new Exception(nameof(this.EstablishReceiver)));
this.RaiseOnErrorToClient(ex);
}
}
DataReceived() 方法:
protected void DataReceived(IAsyncResult result)
{
var state = (StateObject) result.AsyncState;
// End the data receiving that the socket has done and get the number of bytes read.
var bytesCount = 0;
try
{
SocketError errorCode;
bytesCount = state.Socket.EndReceive(result, out errorCode);
if (errorCode != SocketError.Success)
{
bytesCount = 0;
}
}
catch (Exception ex)
{
this.RaiseOnErrorToClient(new Exception(nameof(this.DataReceived)));
this.RaiseOnErrorToClient(ex);
}
if (bytesCount > 0)
{
// Convert the data we have to a string.
this.DataBuffer += Encoding.UTF8.GetString(state.Buffer, 0, bytesCount);
// Record last time data received
this.LastDataReceivedOn = DateTime.UtcNow;
this.RaiseOnDataReceivedToClient(this.DataBuffer);
this.DataBuffer = string.Empty;
this.EstablishReceiver();
}
}
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
上面的 DataReceived()
方法还包含对第二个异常的修复。异常是由在断开连接的套接字上调用 BeginReceive()
(从 EstablishReceiver()
)引起的。如果之前的读取带来了 0 个字节,则不应在套接字上调用 BeginReceive()
。
关于c# - 调用 EndReceive 和 BeginReceive 时出现 TcpClient 异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49244274/
我正在尝试使用 Socket.BeginReceive(...) 和 Socket.EndReceive(...) 作为我的 UDP 数据包接收器客户端。它按预期接收和处理数据包,但是,当我希望取消和
我是编程新手,对异步套接字编程感到困惑。 例如,假设我有两个 BeginSend,一个接一个。第一个发送一百万个字符,第二个仅发送 64 个字符。 由于异步性质,第二个 BeginSend 不会在第一
我一直在查看处理来自 MSMQ 的消息的服务的示例代码。在代码中,在 ReceiveCompletedEventHandler 的开头立即调用 EndReceive() 方法,然后它开始实际处理消息的
当以 1024 字节的 block 读取数据时,我如何继续从接收大于 1024 字节的消息的套接字中读取数据,直到没有数据为止?我是否应该只使用 BeginReceive 只读取数据包的长度前缀,然后
我的 TCP 客户端在接收数据时卡住了。 已建立连接 客户端发送 21 个字节。 (见#5) 客户端上的下一个 BeginReceive 调用永远不会调用回调。当我强制它调用 EndReceive 时
关于 microsoft site您可以找到 ReadCallback(IAsyncResult) 的代码 static void ReadCallback(IAsyncResult ar) {
我正在套接字上进行以下 BeginReceive 调用: m_socket.BeginReceive(m_buffer, 0, m_buffer.Length, SocketFlags.Partial
要从套接字异步接收数据,.Net 支持对称的 BeginReceive/EndReceive 调用。基本上你调用BeginReceive()开始监听并确定数据到达时应调用的回调。在回调中调用 EndR
Socket.BeginReceive/EndReceive 函数的调用顺序是什么? 例如,我两次调用 BeginReceive,一次是为了获取消息长度,第二次是为了获取消息本身。现在的场景是这样的,
我需要接收异步消息。 在所有消息中,前 2 个字节表示下一个字节数组的长度。我的问题是在少数情况下我会收到意外的数据包。 如果我使用 Thread.Sleep(200)这个问题不会发生,或者很少发生。
问题: 当我做这样的事情时: for (int i = 0; i < 100; i++) { SendMessage( sometSocket, i.ToString()); Thre
背景: 我正在编写的应用程序使用异步套接字(使用 BeginSend、EndSend、BeginReceive、EndReceive)在彼此之间发送数据。 IPV4 上的套接字是 TCP,没有套接字标
我正在开发一个 C# 程序,我想在其中与 wifi 模块 ( RN 171 ) 交谈。 在我的 Program.cs 中,当我收到 RabbitMQ 消息时,我直接调用我的 Start 方法。 我从
我无法从文档中看出这两者之间的区别: Socket.EndReceive Method (IAsyncResult, SocketError) Socket.EndReceive Method (IA
我在 Windows 服务中使用异步回调来接收网络上的 UDP 数据广播。 回调使用 UDPClient.EndReceive() 方法来结束挂起的异步接收。在服务 OnStop() 方法期间,我 U
我在 SubscriptionClient 上调用 BeginReceive(),如下所示: client.BeginReceive(new TimeSpan(6, 0, 0), new AsyncC
我正在尝试实现包装器类,它将简单地连接到 TCP 服务器并等待数据。一旦数据从服务器提交 - 我将收到此数据并将其传递给我类(class)的订阅者。 这一切都有效。现在我想添加外部功能以在计时器上“重
我在 Windows 服务中使用 MSMQ。 当服务暂停时,我想关闭 MSMQ 并在服务恢复时重新打开它。 代码如下所示: 开始 _mq.ReceiveCompleted += this.Receiv
这与我上一个问题类似。我正在制作一个简单的 tcp/ip 聊天程序,但在使用 EndReceive Callback 函数时遇到了一些困难。我粘贴了 Microsoft 的实现(见下文),我注意到如果
我正在使用 Service Bus 2.1 For Windows Server,并且我有一种异步接收消息的方法。 我的方法的主体是: var waitTimeout = TimeSpan.FromS
我是一名优秀的程序员,十分优秀!