我正在编写一个将系统日志发送到中央服务器的应用程序。到服务器的网络连接预计不可靠。由于这个原因,我需要能够检查服务器是否已接收到消息,以便如果发送失败,我可以稍后再尝试发送。
我无法控制服务器,只能控制与服务器建立TCP连接的能力-我见过的大多数问题都建议编写自定义ACK逻辑,但这对我来说不是一个选择。我需要一种完全基于客户端的方法。有什么方法可以访问TCP确认以将消息标记为已发送?
答案 0 :(得分:2)
TCP协议可确保在远程服务器上正确传递数据。引用RFC 793中原始的TCP规范:
TCP的确认不能保证数据已经被 交付给最终用户,但仅接收方TCP已采用 这样做的责任。
因此,如果您没有从发送端收到错误,则可以确认删除服务器TCP堆栈已正确接收了您的数据。 TCP内置检测损坏,丢失,重复或乱序传送的数据包(使用序列号)的功能,并在检测到问题时会重新传输数据包。
答案 1 :(得分:1)
正如其他发布者所提到的,TCP是可靠的协议。您可以将其包装在一些异常处理代码中,以确保在恢复连接时重新发送消息,例如:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace TCPClientTest
{
class SyslogMessage
{
public Guid Guid = Guid.NewGuid();
public byte[] MessageData;
}
class Program
{
static readonly int TCP_PORT = 1337;
static byte[] SendTCPMessage(String hostname, int port, byte[] data)
{
using (var client = new TcpClient(hostname, port))
{
using (var stream = client.GetStream())
{
stream.Write(data, 0, data.Length);
var responseData = new byte[1024];
var byteCount = stream.Read(responseData, 0, responseData.Length);
return responseData.Take(byteCount).ToArray();
}
}
}
static void SendSyslog(String hostname, int port, SyslogMessage m)
{
SendTCPMessage(hostname, port, m.MessageData);
}
static Queue<SyslogMessage> sysLogQueue = new Queue<SyslogMessage>(new List<SyslogMessage>()
{
new SyslogMessage() { MessageData = Encoding.UTF8.GetBytes("Test data 1")},
new SyslogMessage() { MessageData = Encoding.UTF8.GetBytes("Test data 2")}
});
static void Main(string[] args)
{
System.Threading.Timer timer = new System.Threading.Timer(SendLogs, null, 1000, 5000);
Console.WriteLine("Press return to continue...");
Console.Read();
}
static void SendLogs(object state)
{
while (sysLogQueue.Count > 0)
{
try
{
var m = sysLogQueue.Peek();
SendSyslog("localhost", TCP_PORT, m);
Console.WriteLine("Sent sys log: " + Encoding.UTF8.GetString(m.MessageData));
// Remove from queue.
sysLogQueue.Dequeue();
}
catch (SocketException e)
{
// Leave in the queue.
Console.WriteLine("Failed to send log: Socket exception occurred: {0}", e);
// Break until next attempt.
break;
}
}
}
}
}
我为此使用了端口1337,只需将其设置为您需要的任何值即可。