验证TCP消息的传递

时间:2018-06-26 13:54:55

标签: c# tcp

我正在编写一个将系统日志发送到中央服务器的应用程序。到服务器的网络连接预计不可靠。由于这个原因,我需要能够检查服务器是否已接收到消息,以便如果发送失败,我可以稍后再尝试发送。

我无法控制服务器,只能控制与服务器建立TCP连接的能力-我见过的大多数问题都建议编写自定义ACK逻辑,但这对我来说不是一个选择。我需要一种完全基于客户端的方法。有什么方法可以访问TCP确认以将消息标记为已发送?​​

2 个答案:

答案 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,只需将其设置为您需要的任何值即可。