小弟做Web Service + Modbus TCP/IP协议远程采集本地模拟的Slave设备,高频下卡死

jndx_xyc 2018-08-06 04:29:05
小弟做Web Service + Modbus TCP/IP协议远程采集本地模拟的Slave设备,采集间隔2s下,系统正常运行,高频下调用webservice方法一定次数后,webservice无响应。程序如下:
1、WebService代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;

namespace AcquisitonWebService
{
/// <summary>
/// AcWebSvr 的摘要说明
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消注释以下行。
// [System.Web.Script.Services.ScriptService]
public class AcWebSvr : System.Web.Services.WebService
{
//建立连接
[WebMethod]
public string Connect()
{

//声明一个socket对象
Socket newClient;
byte[] outData = new byte[] { 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, 0x02 };
//创建套接字
IPEndPoint addIe = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 502);
//实例化newClient对象,初始化
newClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//设置receive超时时间
newClient.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, -100);
try
{
//进行连接
newClient.Connect(addIe);
}
catch (SocketException e)
{
return e.Message;
}
//发送指令
newClient.Send(outData);
//读取数据
string dataStr = null;
//while (dataStr == null)
//{
try
{
byte[] inData = new byte[1024];
//接受数据
newClient.Receive(inData, 0, 1000, SocketFlags.None);
int length = inData[5];
byte[] dataShow = new byte[length + 6];
//将数据转移到dataShow中
for (int i = 0; i < length + 6; i++) { dataShow[i] = inData[i]; }
//二进制转化为对应的字符型
dataStr = BitConverter.ToString(dataShow);
}
catch (SocketException e)
{
return e.Message;
}
catch (IOException e)
{

return e.Message;
}
catch (Exception e)
{
return e.Message;
}
//}
return dataStr;
}
}
}


2、客户端代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;

namespace AcquisitionClient
{
public partial class DataMonitoring : Form
{

//实例化温度泛型
private List<double> dataReceive = new List<double>(80);
//实例化湿度泛型
private List<double> dataReceive2 = new List<double>(80);
//实例化时间泛型
private List<double> dataTime = new List<double>(80);
//声明线程
private Thread dataAcquisitionThread;
//设定起始数为0
private int i = 0;
//声明webservice服务对象
DataWebAcquisition.AcWebSvr myDataAcquisition = new DataWebAcquisition.AcWebSvr();
//实例化对象

/// <summary>
/// 窗体 加载初始化
/// </summary>
public DataMonitoring()
{
InitializeComponent();
}
/// <summary>
/// 开始/结束监测数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void DataMonitorButton_Click(object sender, EventArgs e)
{
switch (DataMonitorButton.Text)
{
case "开始监测":
dataAcquisitionThread = new Thread(new ThreadStart(this.ChartDraw));
dataAcquisitionThread.Start();
DataMonitorButton.Text = "结束监测";
break;
case "结束监测":
if (dataAcquisitionThread.IsAlive) dataAcquisitionThread.Abort();
TemperatureChart.Series["温度"].Points.Clear();
humidityChart.Series["湿度"].Points.Clear();
dataReceive2.Clear();
dataReceive.Clear();
dataTime.Clear();
i = 0;
DataMonitorButton.Text = "开始监测";
break;
}

}
/// <summary>
/// 获取数据以及绘制图标
/// </summary>
public void ChartDraw()
{
while (true)
{
string msg = myDataAcquisition.Connect();
//DataReceiveTxt.AppendText(msg + "\r\n");
try
{
//加入到绘图Y轴泛型中
string[] msgList = msg.Split(new char[] { '-' });
dataReceive.Add(Convert.ToDouble(Convert.ToInt32(msgList[msgList.Length - 1], 16)));
dataReceive2.Add(Convert.ToDouble(Convert.ToInt32(msgList[msgList.Length - 3], 16)));
//加入到绘图X轴泛型中
double n = Convert.ToDouble(i);
n = Math.Round(n * 2, 2);
dataTime.Add(n);

//调用主线程invoke方法绘制chart图标
if (TemperatureChart.IsHandleCreated)
{
////实例化一个委托指向一个方法,兵通过委托对象使用该方法
//myDelegate myInvoke = new myDelegate(UpdateCpuChart);
//TemperatureChart.Invoke(myInvoke);
//建立匿名委托,指向某方法
this.Invoke((MethodInvoker)delegate () { UpdateCpuChart(); });
}
Thread.Sleep(200);
i = i + 1;
}
catch
{
MessageBox.Show(msg);
Thread.Sleep(5000);
}
}
}

/// <summary>
/// 更新chart表
/// </summary>
public void UpdateCpuChart()
{
TemperatureChart.Series["温度"].Points.AddXY(dataTime[i], dataReceive[i]);
humidityChart.Series["湿度"].Points.AddXY(dataTime[i], dataReceive2[i]);
}

/// <summary>
/// 暂停采集
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void AcqusitionSuspendButton_Click(object sender, EventArgs e)
{
switch (AcquisitionSuspendButton.Text)
{
case "暂停":
if (dataAcquisitionThread.IsAlive)
dataAcquisitionThread.Suspend();
AcquisitionSuspendButton.Text = "重连";
break;
case "重连":
dataAcquisitionThread.Resume();
AcquisitionSuspendButton.Text = "暂停";
break;
}
}
/// <summary>
/// 窗体退出时,进行的操作
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void DataMonitoring_FormClosing(object sender, FormClosingEventArgs e)
{
System.Environment.Exit(0);
}
}
}



3、遇到的问题
(1)低频率,2s采集间隔下,程序正常运行,如下图:
将,休眠时间改为2000ms:
Thread.Sleep(2000);
i = i + 1;
,运行结果:
slave设置:


程序稳定运行:


(2)高频下,采集间隔200ms。经过调试和错误处理,会出现如下问题,初步判定,问题出在socket.Receive()方法响应超时。
问题:程序同一时间点出错,且一段时间后恢复,然后过一段时间后又卡住。


应用池设置:


此时:
iis服务没有崩溃,进行应用池回收后,再启动客户端程序,可以正常采集,但还是到同一时间点后,receive方法得不到响应。
小弟更改过iis服务里面的请求队列,并发数和请求数,都没有作用,请问大佬们,这个问题具体应该如何解决呢???
感激不尽!
...全文
767 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
墨方士 2019-09-29
  • 打赏
  • 举报
回复
楼主是不是Tcp连接出现被拒绝情况 通过PLC专业软件查看 连接繁忙中
palhotel 2018-08-07
  • 打赏
  • 举报
回复
其实你应该做两个程序,一个是专门tcp通信的,一个是专门提供web接口的,这两个进程之间通信来交换数据,可以通过文件、数据库、网络等方法。看不懂你的程序,好像是调用一次web接口,就启动tcp服务端,但是你绑定的同一个端口,肯定不行。
jndx_xyc 2018-08-06
  • 打赏
  • 举报
回复
引用 3 楼 adaloceyou 的回复:
可以看看进程管理器,cpu、内存占用、句柄数,找找问题所在


大神讲的太高端了,我去查查资料试试!
jndx_xyc 2018-08-06
  • 打赏
  • 举报
回复
引用 4 楼 diaodiaop 的回复:
这种东西干嘛用webservice啊 http就http socket 就socket 你混合起来 怎么可能行.

而且 你一秒一请求5次http 本身也不太可能...

是这样的,socket用于本地服务器和设备间的通信,http用于服务器和远程客户机的连接。。。您知道提高http在一段时间内请求数的方法吗?
引用
??
jndx_xyc 2018-08-06
  • 打赏
  • 举报
回复
引用 1 楼 qq_28194303 的回复:
看不出来。我看你每次都新建Socket对象连接(没必要啊),也没有释放。会不会是调用频率高 ,Socket没有来得及释放呢?

是这样的,我自己搭的本地服务器,这个服务器用来采集一个设备的数据,服务器和这个设备是通过Modbus TCP/IP协议通信的,服务器和客户端是通过webservice进行远程访问的。因为远程调用webservice的方法每次都会初始化属性,所以我只能里面每次都会实例化一个对象。。。对于第一个请求和第二个请求重叠的问题,receive方法不是阻塞的吗?没返回值的话,webservice的方法也不会有远程返回值呀?程序不应该是被挂起的嘛?
by_封爱 2018-08-06
  • 打赏
  • 举报
回复
这种东西干嘛用webservice啊 http就http socket 就socket 你混合起来 怎么可能行.

而且 你一秒一请求5次http 本身也不太可能...
palhotel 2018-08-06
  • 打赏
  • 举报
回复
可以看看进程管理器,cpu、内存占用、句柄数,找找问题所在
晨易夕 2018-08-06
  • 打赏
  • 举报
回复
比如你第一个请求还在执行


//接受数据
newClient.Receive(inData, 0, 1000, SocketFlags.None);


你第二个请求又来了。
晨易夕 2018-08-06
  • 打赏
  • 举报
回复
看不出来。我看你每次都新建Socket对象连接(没必要啊),也没有释放。会不会是调用频率高 ,Socket没有来得及释放呢?

12,162

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 Web Services
社区管理员
  • Web Services社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧