在连接服务器时,对于连接服务器的工具类只能创建一次,要不然在有心跳程序的情况下会出现服务器与客户端连接正常但是重复连接服务器的过程,心跳程序是针对一次连接但是出现断开的情况而设计的。
一。出现的问题
1.配置文件写错,搞了半天才发现,下次别手贱乱改配置文件
2.在启动服务的OnStart方法里要开启一个新的线程连接Java服务器以及OPC服务器,在OnMessage最好也开启一个新的线程处理接受到的消息
2.Json数据转换,对于内嵌的Json数据,需要使用类作为容器容纳此内嵌的Json数据
eg.{
"Name": "cy",
"Age": 28,
"Alive": false,
"FavoriteFilms": null,
"Child": {
"Name": "lj",
"Age": 12,
"Alive": true,
"Child": null
}
}
Child这个字段的Json数据就需要使用一个类Child来表示
使用方法
Class:ConnectBean
[DataContract]
class ConnectBean
{
[DataMember(Order = 0, IsRequired = true)]
public String id { get; set; }
[DataMember(Order = 1)]
public String cmd { get; set; }
[DataMember(Order = 2)]
public Data data { get; set; }
[DataMember(Order = 3)]
public String uuid { get; set; }
public ConnectBean() {
}
public ConnectBean(String id, String cmd, Data data, String uuid) {
this.id = id;
this.cmd = cmd;
this.data = data;
this.uuid = uuid;
}
}
Class:Data
[DataContract]
class Data
{
[DataMember(Order = 0, IsRequired = true)]
public String Value { get; set; }
[DataMember(Order = 1)]
public String Quality { get; set; }
[DataMember(Order = 2)]
public String TimeStamp { get; set; }
}
public static String Bean2JsonMethod(ConnectBean cb) {
//将ConnectBean对象序列化为Json
DataContractJsonSerializer serializer = new DataContractJsonSerializer(cb.GetType());
//创建存储区为内存流
MemoryStream ms = new MemoryStream();
//将Json字符串写入内存流中
serializer.WriteObject(ms, cb);
System.IO.StreamReader reader = new StreamReader(ms);
ms.Position = 0;
string strRes = reader.ReadToEnd();
reader.Close();
ms.Close();
return strRes;
}
当时用序列化和反序列化转换数据格式的时候使用[Serializable]会导致转化出来的Json数据变成"<cmd>k__BackingField"这种格式,需要使用 [DataContract]这种方法才行。
3.
cd C:\Windows\Microsoft.NET\Framework\v4.0.30319\
InstallUtil 路径地址\OpcClient.exe 安装服务
InstallUtil /u 路径地址\OpcClient.exe 卸载服务
net start 服务名 启动服务
net stop服务名 停止服务
4.当使用记录日志的方法时,如果多个线程同时操作一个日志文件可能会出现异常,导致服务崩溃,避免多个线程会同时操作一个日志文件。
5.链接OPC服务器设备源码
class ConnectOpc
{
//private LoggerManagerUtil log = new LoggerManagerUtil();
public Boolean connectOpcState { get; set; } = false;//OPC服务器是否连接成功的标志位
public ConnectServer cs { get; set; }
private OPCServer objServer;//OPCServer类
private OPCGroups objGroups;//通过OPCServer创建OPCGroups组
private OPCGroup objGroup;//
private OPCItems objItems;
private Array strItemIDs;//Items的数组形式,2个Item上的话,需要创建3个空间,使用后边2个
private Array lClientHandles;//客户端句柄,通过Items创建,2个Item上的话,值为0,1,2,一般使用1和2
private Array lserverhandles;//OPC服务器端句柄,添加OPC标签Items后通过OPC服务器端赋值
private Array lErrors;//添加OPC标签Items时OPC服务器端返回的错误信息
// int ltransID_Rd = 1;
// int lCancelID_Rd;
private object RequestedDataTypes = null;
private object AccessPaths = null;
// Array lerrors_Rd;
private Array lErrors_Wt;
private int lTransID_Wt = 2;
private int lCancelID_Wt;
public void ConnectOpcMethod() {
try {
//(1)创建opc server对象
objServer = new OPCServer();
//连接opc server
objServer.Connect("Matrikon.OPC.Simulation.1", null);
//objServer.Connect("OPCServer.WinCC.1", null);
//(2)建立一个opc组集合
objGroups = objServer.OPCGroups;
int a = objServer.ServerState;
//(3)建立一个opc组
objGroup = objGroups.Add(null); //Group组名字可有可无
//(4)添加opc标签
objGroup.IsActive = true; //设置该组为活动状态,连接PLC时,设置为非活动状态也一样
objGroup.IsSubscribed = true; //设置异步通知
objGroup.UpdateRate = 200;
objServer.OPCGroups.DefaultGroupDeadband = 0;
objGroup.DataChange += new DIOPCGroupEvent_DataChangeEventHandler(KepGroup_DataChange);
//objGroup.AsyncReadComplete += new DIOPCGroupEvent_AsyncReadCompleteEventHandler(AsyncReadComplete);
//objGroup.AsyncWriteComplete += new DIOPCGroupEvent_AsyncWriteCompleteEventHandler(AsyncWriteComplete);
objItems = objGroup.OPCItems; //建立opc标签集合
string[] tmpIDs = new string[4];
int[] tmpCHandles = new int[4];
for (int i = 1; i < 4; i++)
{
tmpCHandles[i] = i;
}
tmpIDs[1] = "Random.Boolean";
tmpIDs[2] = "Random.Boolean";
tmpIDs[3] = "Triangle Waves.Int4";
strItemIDs = (Array)tmpIDs;//必须转成Array型,否则不能调用AddItems方法
lClientHandles = (Array)tmpCHandles;
// 添加opc标签
objItems.AddItems(3, ref strItemIDs, ref lClientHandles, out lserverhandles, out lErrors, RequestedDataTypes, AccessPaths);
connectOpcState = true;
}
catch (Exception e) {
//log.LogManage("连接OPC异常,原因:" + e.Message);
}
}
//同步写
private void Write_Syn(String str)
{
try {
if (!connectOpcState) {
ConnectOpcMethod();
}
int NumItems = 1;
int[] Handles = new int[2];
Handles[1] = Convert.ToInt32(lserverhandles.GetValue(3));
Array ServerHandles = (Array)(Handles);
object[] data = new object[2];
//data[1] = (object)Write1.Text;
data[1] = (object)str;
Array Values = (Array)data;
Array Errors;
objGroup.SyncWrite(NumItems, ref ServerHandles, ref Values, out Errors);
}
catch (Exception ex) {
//log.LogManage("向OPC写入数据异常,原因:" + ex.Message);
DisConnect();
}
}
//异步写完成
//private void AsyncWriteComplete(int TransactionID, int NumItems, ref Array ClientHandles, ref Array Errors)
//{
// throw new NotImplementedException();
//}
//订阅方式读
private void KepGroup_DataChange(int TransactionID, int NumItems, ref Array ClientHandles, ref Array ItemValues, ref Array Qualities, ref Array TimeStamps)
{
try {
//为了测试,所以加了控制台的输出,来查看事物ID号
//Console.WriteLine("********"+TransactionID.ToString()+"*********");
//订阅方式读,读到的数据通过ConnectServer的Send方法发送给Java服务器
for (int i = 0; i < NumItems; i++)
{
if (Convert.ToInt32(ClientHandles.GetValue(i + 1)) == 1)
{
if (ItemValues.GetValue(i + 1) != null)
{
//this.Value1.Text = ItemValues.GetValue(i + 1).ToString();
//this.Quality1.Text = Qualities.GetValue(i + 1).ToString();
//this.TimeStamp1.Text = TimeStamps.GetValue(i + 1).ToString();
//ConnectBean cb = new ConnectBean("1","test_read","",2);
//cs.send(Bean2JsonUtil.Bean2JsonMethod(cb));
String Value= ItemValues.GetValue(i + 1).ToString();
String Quality = Qualities.GetValue(i + 1).ToString();
String TimeStamp = TimeStamps.GetValue(i + 1).ToString();
String msg = OpcDataDealUtil.OpcDataDealMethod(Value,Quality,TimeStamp);
cs.send(msg);
}
}
if (Convert.ToInt32(ClientHandles.GetValue(i + 1)) == 2)
{
if (ItemValues.GetValue(i + 1) != null)
{
//this.Value2.Text = ItemValues.GetValue(i + 1).ToString();
//this.Quality2.Text = Qualities.GetValue(i + 1).ToString();
//this.TimeStamp2.Text = TimeStamps.GetValue(i + 1).ToString();
//ConnectBean cb = new ConnectBean("1", "test_read", "", 2);
//cs.send(Bean2JsonUtil.Bean2JsonMethod(cb));
String Value = ItemValues.GetValue(i + 1).ToString();
String Quality = Qualities.GetValue(i + 1).ToString();
String TimeStamp = TimeStamps.GetValue(i + 1).ToString();
String msg = OpcDataDealUtil.OpcDataDealMethod(Value, Quality, TimeStamp);
cs.send(msg);
}
}
if (Convert.ToInt32(ClientHandles.GetValue(i + 1)) == 3)
{
if (ItemValues.GetValue(i + 1) != null)
{
//this.Value3.Text = ItemValues.GetValue(i + 1).ToString();
//this.Quality3.Text = Qualities.GetValue(i + 1).ToString();
//this.TimeStamp3.Text = TimeStamps.GetValue(i + 1).ToString();
//ConnectBean cb = new ConnectBean("1", "test_read", "", 2);
//cs.send(Bean2JsonUtil.Bean2JsonMethod(cb));
String Value = ItemValues.GetValue(i + 1).ToString();
String Quality = Qualities.GetValue(i + 1).ToString();
String TimeStamp = TimeStamps.GetValue(i + 1).ToString();
String msg = OpcDataDealUtil.OpcDataDealMethod(Value, Quality, TimeStamp);
cs.send(msg);
}
}
}
}
catch (Exception e) {
//log.LogManage("订阅数据异常,原因:" + e.Message);
DisConnect();
}
}
//关闭OPC连接
private void DisConnect()
{
try {
if (objServer != null)
{
objServer.Disconnect();
}
connectOpcState = false;
//关闭kepserver进程,这个跟OPC操作无关
/*
foreach ( Process oneProcess in Process.GetProcesses())
{
if (oneProcess.ProcessName == "ServerMain")
oneProcess.Kill();
}
*/
}
catch (Exception ex) {
//log.LogManage("关闭OPC连接异常,原因:" + ex.Message);
connectOpcState = false;
}
}
}