我在这个问题上挣扎了几天。我有一台服务器机器,我需要实现一个客户端。首先,我发送登录消息并收到响应。之后,我将需要发送和接收不同的消息。从 10 到 10 秒,我需要发送一个“心跳消息”,因此服务器需要知道连接仍然处于活动状态。我使它成为一个简单的异步客户端。
private static void Send(Socket client, String data)
{
byte[] byteData = charTobyte(data.ToCharArray());
client.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), client);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = client.EndSend(ar);
Console.WriteLine("Sent {0} bytes to server.", bytesSent);
sendDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace + " " + e.Message);
}
}
private static void Receive(Socket client)
{
try
{
// Create the state object.
StateObject state = new StateObject();
state.workSocket = client;
// Begin receiving the data from the remote device.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void ReceiveCallback(IAsyncResult ar)
{
try
{
// Retrieve the state object and the client socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
// Read data from the remote device.
int bytesRead = client.EndReceive(ar);
if (bytesRead > 0)
{
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
else
{
// All the data has arrived; put it in response.
if (state.sb.Length > 1)
{
response = state.sb.ToString();
Console.WriteLine("Response: " + response);
}
receiveDone.Set();
}
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace + " " + e.Message);
}
}
private static void Heartbeat(object source, System.Timers.ElapsedEventArgs e, Socket client)
{
try
{
Console.WriteLine("Heartbeat...sent");
SendHeart(client, DPLHeader(HeartBeat));
sendHeart.WaitOne();
}
catch (Exception ex)
{
Console.WriteLine(ex.StackTrace + " " + ex.Message);
}
finally
{
Console.WriteLine("value: " + client.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive) + " : " + client.Connected);
}
}
这就是我在 StartClient() 中所做的:
public static void StartClient()
{
// Connect to a remote device.
try
{
client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
// Connect to the remote endpoint.
client.BeginConnect(remoteEP,
new AsyncCallback(ConnectCallback), client);
connectDone.WaitOne();
timer.Interval = 10000;
timer.Elapsed += new System.Timers.ElapsedEventHandler((source, e) => Heartbeat(source, e, client));
timer.Enabled = false;
timer.AutoReset = false;
timer.Start();
message = DPLHeader(Messages.ElementAt(j));
Send(client, message);
sendDone.WaitOne();
Console.WriteLine("value: " + client.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive) + " : " + client.Connected);
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace + " " + e.Message);
}
}
SendHeart() 就像普通的 Send 一样,只是发送 keepalive 消息。
我面临的问题是下一个:在第一次使用计时器并触发 Heartbeat() 之后,应用程序只发送 keepalive 消息,因此它不会发送其他消息。如果它只发送 keepalive 消息,则连接保持活动状态。就像客户端无法再访问 Send 回调一样,它仍然只用于 Heartbeat。
在另一种情况下,我制作了 3 个计时器,一个用于 Send(),一个用于 Receive(),一个用于 Heartbeat()。按照这个顺序,当一个计时器到期时,它会停止并启动下一个计时器,依此类推。我发送一条消息,我阅读了一个响应并发送了一个 Heartbeat,之后我尝试执行 BeginSend a message 或 BeginReceive a message 的任何动作,连接被主机中止。
对于第二种情况,另一个问题是,如果在发送消息后启动接收,如果发送了心跳,接收线程将丢失,因此我无法再读取消息。
很抱歉,如果它太纠结了。如果您不理解某些内容,我正在等待问题。谢谢