Leon良木 2022-07-25 15:15 采纳率: 0%
浏览 883

socket 与西门子PLC仿真通讯时报错:远程主机强迫关闭了一个现有的连接。

使用socket 与西门子PLC仿真通讯时,连接plc没有问题,读取数据时报错:远程主机强迫关闭了一个现有的连接。
定位到代码 tcpClient.Receive(buffer, SocketFlags.None);

相关截图

img

img

相关代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using thinger.DataConvertLib;
using xktComm;

namespace FrmLogin
{
    public partial class FrmMain : Form
    {
        public FrmMain()
        {
            InitializeComponent();


            SiemensS7 s7 = new SiemensS7();




            //取消跨线程访问问题
            Control.CheckForIllegalCrossThreadCalls = false;
        }

        //声明一个socket对象
        Socket tcpClient;

        //创建取消数据源
        private CancellationTokenSource cts;//= new CancellationTokenSource();

        bool isConn;
        /// 
        /// 连接PLC
        /// 
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Btn_Conn_Click(object sender, EventArgs e)
        {
            if (this.btn_Conn.Text == "连接")
            {
                //实例化
                tcpClient = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
                cts = new CancellationTokenSource();
                EndPoint ep = new IPEndPoint(IPAddress.Parse(txtb_IPAddress.Text), int.Parse(txtb_Port.Text));

                try
                {
                    tcpClient.Connect(ep);
                    this.btn_Conn.Text = "断开";
                    this.btn_Conn.BackColor = Color.Green;
                    isConn = true;
                }
                catch (Exception ex )
                {
                    ShowMessage("连接失败:" + ex.Message);
                    return;
                }

                Task.Run(new Action(() =>
                {
                    GetPLCValue();
                }));

            }
            else
            {
                tcpClient?.Close();
                cts.Cancel();
                isConn = false;
                this.btn_Conn.Text = "连接";
                this.btn_Conn.BackColor = DefaultBackColor;
            }
                
        }

        int i = 0;

        private void GetPLCValue()
        {
            while (isConn)//(!cts.IsCancellationRequested)
            {
                Thread.Sleep(10);
                byte[] buffer = new byte[200];
                int length = -1;

                try
                {
                    length = tcpClient.Receive(buffer,SocketFlags.None);
                }
                catch (Exception ex)
                {
                  //  i += 1;
                    ShowMessage("本次数据读取失败:" + ex.Message);
                }

                if (length == 20 )
                {
                    byte[] result = thinger.DataConvertLib.ByteArrayLib.GetByteArrayFromByteArray(buffer,0,length);

                    float aa = thinger.DataConvertLib.FloatLib.GetFloatFromByteArray(result, 0, DataFormat.ABCD);
                    txtsh_data.VarValue = aa.ToString();

                }
                


            }
        }



        /// 
        /// 清空显示信息
        /// 
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Btn_Clear_Click(object sender, EventArgs e)
        {
            this.txtb_Message.Clear();
            i = 0;
        }

        private void ShowMessage(string str)
        {
            if (!txtb_Message.Text.Contains(str))
            {
                txtb_Message.AppendText(str + "\r\n");
            }
        }

        private void Button1_Click(object sender, EventArgs e)
        {
            byte[] buffer = new byte[200];
            int length = -1;

            try
            {
                length = tcpClient.Receive(buffer, SocketFlags.None);
            }
            catch (Exception ex)
            {
                i += 1;
                ShowMessage("本次数据读取失败:" + (i).ToString() + "次:" + ex.Message);
            }

            if (length == 20)
            {
                byte[] result = thinger.DataConvertLib.ByteArrayLib.GetByteArrayFromByteArray(buffer, 0, length);

                float aa = thinger.DataConvertLib.FloatLib.GetFloatFromByteArray(result, 0, DataFormat.ABCD);

                //     ShowMessage(aa.ToString());

            }




        }
    }
}


使用网口助手和PLC进行通讯正常,使用网口助手做服务器,C#程序做客户端也能正常通讯,但是使用C#程序做客户端访问plc服务器时报错。

  • 写回答

4条回答 默认 最新

  • wanghui0380 2022-07-25 15:47
    关注

    plc作为硬件只支持有限连接-----原因你应该可以想到,单片也好,plc也罢毕竟都是单一芯片,有限内存
    所以当一个连接连接上去,长时间不发数据包,也不发心跳。他会认为你在玩他,所以会一脚把你T了

    当然这代码目前看来毛病也不少,不过到不是你现在问题的原因,现在的问题其实错误本身就告诉你了“远程主机主动断开”--就是说远程主机主动发送了一个“close”或者“abandon”给你

    你说,你用网口助手测试过,那么请在网口助手上主动关闭服务模拟 或者 主动close你这个client看看,你会模拟出这种错误异常来

    ps:实际开发中tcp有窗口机制,所以你这里legth==20 不靠谱,同时因为窗口机制,对方发送会等待你缓冲区确认,如果你这里太过耗时,那么对方可能收到一个timeout异常,通常情况下俺们大部分人的处理方式就是如果tmeout我就主动close了,这样你也会得到一个“主动关闭”的异常

    另外在附加一些常规服务器认为应该把你T掉的原因:
    1.长时间没有任何主动性动作,T掉
    2. Tcp窗口时间内,发送后长期不给确认,发送超时,T掉
    3.长期发送错误数据包格式或伪造数据包格式,T掉
    4.任何会引发 await Task.WhenAll (接收任务,发送任务) 这个异常的client,T掉

    评论 编辑记录

报告相同问题?

问题事件

  • 创建了问题 7月25日