TCP套接字服务器取决于服务代理,我如何收到整个消息并发送响应?

时间:2015-05-19 13:04:28

标签: c# sql-server sockets tcp sqldependency

我正在设置一个需要执行一些操作的应用程序... 1.)从tcp套接字接收一串xml数据。 2.)将此数据插入到sql表中。 3.)触发器更新这些表中的大量内容并将它们放入输出表中。 4.)Sql Dependencies确认已将记录插入到输出表中,并且需要通过同一套接字发送回复。

我遇到的问题是,如果我从客户端将整个邮件发送到服务器,我必须.Close客户端,这使得无法收到回复,如果我不知道#39; t .Close客户端,只要消息适合一个数据包,我就可以收到响应(如果服务器收到的消息太长则会被切断,因此会抛出错误) 。我怎样才能做到这一点?所以现在亏本,如果有任何其他信息需要帮助这项工作让我知道。我即将接近该计划的截止日期,并且真的希望能够让它发挥作用。

这是我的客户代码:

private void SendMessage(string input, TcpClient client)
{
    // Ensure some xml data has been provided.
    string Error = string.Empty;
    if (input == string.Empty)
    {
        Error += "You cannot send an empty xml string\r";
        Textbox_FauxXMLSend.Focus();
    }

    // Prompt user to correct data if needed.
    if (Error != string.Empty)
    {
        MessageBox.Show(Error, "Send XML", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return;
    }

    try
    {
        // Send and receive the provided xml data.
        using (NetworkStream networkStream = client.GetStream())
        {
            byte[] outStream = System.Text.Encoding.ASCII.GetBytes(input + "\0");
            networkStream.Write(outStream, 0, outStream.Length);
            networkStream.Flush();
            byte[] inStream = new byte[10025];
            networkStream.Read(inStream, 0, (int)client.ReceiveBufferSize);
            string returndata = System.Text.Encoding.ASCII.GetString(inStream);
            Textbox_FauxXMLReceive.Text += (returndata) + "\n";
        }
        _requestCount++;
        lblRequestCount.Text = string.Format("Request Count: {0}", _requestCount.ToString());
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.ToString(), "Send Message Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        CloseConnection(client);
    }
}

服务器的接收端:

private void ReceivePortMessages()
{
    string debug = string.Empty;
    try
    {
        Debug.Print(" >> Starting Server");
        IPAddress ipAddress = Dns.GetHostEntry(Dns.GetHostName()).AddressList.FirstOrDefault(ip => ip.AddressFamily == AddressFamily.InterNetwork);
        _TcpListener = new TcpListener(ipAddress, TcpPort); ;
        Debug.Print(string.Format("{0}:{1}", ipAddress.ToString(), TcpPort.ToString()));
        _TcpListener.Start();

        Stopwatch sw = new Stopwatch();
        do
        {
            try
            {
                _TcpClient = _TcpListener.AcceptTcpClient();
                Debug.Print(" >> Accept connection from client");
                NetworkStream networkStream = _TcpClient.GetStream();
                int receivingBufferSize = (int)_TcpClient.ReceiveBufferSize;
                byte[] bytesFrom = new byte[receivingBufferSize];
                int Read = 0;
                string dataFromClient = string.Empty;
                if (!sw.IsRunning)
                {
                    sw.Start();
                }

                Read = networkStream.Read(bytesFrom, 0, receivingBufferSize);
                dataFromClient = System.Text.Encoding.ASCII.GetString(bytesFrom);
                dataFromClient = dataFromClient.Substring(0, dataFromClient.IndexOf("\0"));
                if (dataFromClient != string.Empty)
                {
                    XmlDocument xm = new XmlDocument();
                    debug = dataFromClient;
                    xm.LoadXml(string.Format("<root>{0}</root>", dataFromClient));
                    XmlElement root = xm.DocumentElement;
                    string rootName = root.FirstChild.Name;
                    RouteInboundXML(rootName, dataFromClient, sw);
                    sw.Restart();
                }
            }
            catch (Exception ex)
            {
                Debug.Print("ReceivePortMessages: " + ex.ToString());
                _TcpClient.Close();
                _TcpListener.Stop();
                ErrorLog.Write("XmlProcessing", ex.ToString() + "\r\n" + "DataFromClient: " + debug, "ReceivePortMessages()");
                return;
            }
        } while (true);
    }
    catch (Exception ex)
    {
        Debug.Print("ReceivePortMessages: " + ex.ToString());
        ErrorLog.Write("XmlProcessing", ex.ToString(), "ReceivePortMessages()");
    }
}

SqlDependency操作之后调用的服务器的发送已经触发并且已生成适当的数据:

private void SendReply(string reply)
{
    try
    {
        NetworkStream networkStream = _TcpClient.GetStream();
        string serverResponse = reply;
        Byte[] sendBytes = Encoding.ASCII.GetBytes(serverResponse);
        networkStream.Write(sendBytes, 0, sendBytes.Length);
        networkStream.Flush();
        Debug.Print(" >> " + serverResponse);
    }
    catch (Exception ex)
    {
        Debug.Print(ex.ToString());
        ErrorLog.Write("XmlProcessing", ex.ToString(), "SendReply()");
    }
}

2 个答案:

答案 0 :(得分:0)

  

我遇到的问题是,如果我从客户端发送到服务器的整个消息,我必须。关闭客户端,这使得无法收到响应

当然,如果你close套接字向服务器发送消息,客户端就不会收到响应。

  

如果我不接受。关闭客户端,只要消息适合一个数据包,我就可以收到响应(如果服务器收到的消息太长则会被切断,因此会丢失一个错误)。

TCP是流协议,不维护消息边界。您的客户端不能假设来自服务器的响应将适合一个数据包。它应该知道服务器响应。对于这个服务器和客户端应该有一个协议。像:

  

响应需要多少字节?将此信息放入交换的消息中。

     

包含响应消息的标记 - 消息开始和消息结束。

基于这些知识,客户应该&#34;预期&#34;可以通过多个read操作得到的响应。因此,在影响中,您不能只有一个read。您应该继续调用read,直到根据应用程序级别的理解读取所需的字节数。

答案 1 :(得分:-1)

请记住,TCP知道 nothing 有关应用程序级别消息的上下文或语义。它只是在比特(井,数据包)周围铲除。

您需要做的是在端点之间定义某种消息交换协议。这样的协议必须定义固定长度的消息格式,或者使用特定的开始和结束字符来描述消息开始和消息结束标记的格式。反过来,这样做将允许您构建一个read()循环,等待符合协议的消息,无论是通过长度还是符号 - 无论您的协议定义了什么。