[#0x0021] throw的屏蔽作用

本文详细解析了Java中异常处理机制的工作原理,特别是throw语句如何影响程序流程及多个异常之间的覆盖效应。通过具体示例说明了throw语句的执行如何导致函数提前退出,并探讨了在异常处理中可能出现的问题。

  在其所在的块内(即{}之内,如方法body、if {...}等)(只是单纯的一对{}不能称为块),throw语句可以屏蔽其后的语句(即在块内,该throw语句后面不能再写其他语句),但在块之外,还是可以写其他的语句的。如:

public class ExceptionTest
{
	private static void func() throws Exception
	{
		throw new Exception();
		//System.out.println("Threw Exception"); //error
	}

	private static void func2() throws Exception
	{
		boolean tag = true;
		
		if (tag)
		{
			throw new Exception();
			//System.out.println("Threw Exception"); //error
		}
		System.out.println("No Exception"); //pass //Mark No.3
	}

	public static void main(String[] args)
	{
		try
		{
			func2(); //Mark No.1
			throw new Exception(); //Mark No.2: direct throw in try
		}
		catch (Exception e)
		{
			System.out.println("Caught Exception");
		}
		
		System.out.println("Continue"); //Mark No.4
	}
}

//output:
/*
	Caught Exception
	Continue
*/

 

  如果不是直接在try中抛出异常(Mark No.2),而是调用会抛出异常的方法(Mark No.1),一旦throw语句执行,则包含该throw语句的函数(如本例的func2())直接退出,后续的语句都不执行(如Mark No.3处就没有运行)。而处理异常的函数(如本例的main())依旧是顺序运行,不会有什么影响,后续的语句继续运行(如Mark No.4处照常运行)。

 

 

2011-10-27 补充:多个throw的覆盖作用

  如果你 throw 了一个 Exception,紧接着后面的 catch/finally 也 throw 了一个 Exception,那么,只有最后抛出的 Exception 才能被外围捕捉,前面 throw 的 Exception 就被覆盖掉了。

 

  一个典型的可能的例子是:

try {
	// 读文件
} finally { 
	if (io != null) {
		io.close();
	}
}

如果读文件时出了 FileNotFoundException,而不巧 io.close() 也出了 IOException,那么外围只能捕捉到 IOException,而真实的原因 FileNotFoundException 却捕捉不到。

 

  《Practical Java》上说可以用一个Collection来保存Exception,最后 throw 出一个 AllException(Collection<Exception> c) 这样的异常出来。但是感觉太麻烦了,估计很少有人这么做。这里记录一下,也只能说是为调试提供一种可能的异常判断思路,真要遇上奇葩的情况,还是自求多福吧……

#region ModbusTCP客户端 /// <summary> /// ModbusTCP客户端 /// </summary> public class ModbusTCP { #region 对象 /*定义连接的Socket*/ Socket ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //---通讯的socket /*定义socket线程*/ Thread receiveTh; //-----------------------接收socket线程 #endregion #region 事件 public del LogInfoDisplay; //----------------------委托变量-信息显示 public Action<string> returnReceiveEvent; //------接收返回数据事件 #endregion #region 变量 /*运行中的状态*/ string nameClient; //---客户端名称 public InfoMsg info = new InfoMsg("", ""); //-----------------------显示信息 /*BIN指令*/ byte[] buffer = new byte[255]; /*接收到的数据*/ byte[] data; //--------数据 /*时间*/ DateTime startTime, stopTime; DateTime stopTime1, stopTime2, stopTime3; #endregion #region 命令枚举 /// <summary> /// 命令枚举 /// </summary> enum Comand : short { 读线圈寄存器 = 1, //-------单个或多个(M寄存器) 读输入状态 = 2, //---------单个或多个 读保存寄存器 = 3, //-------单个或多个(D寄存器) 读输入寄存器 = 4, //-------单个或多个 写单个线圈寄存器 = 5, //---(M寄存器) 写单个保存寄存器 = 6, //---(D寄存器) 写多个线圈寄存器 = 15, //--(M寄存器) 写多个保持寄存器 = 16, //--(D寄存器) } #endregion #region 客户端初始化 /// <summary> /// 客户端初始化 /// </summary> /// <param name="name">客户端名称</param> /// <param name="receiveData">接收数据事件</param> /// <param name="info">消息显示事件</param> public void Initial(string name = "客户端", Action<string> receiveData = null, del info = null) { nameClient = name; //-------------------客户端名称 returnReceiveEvent += receiveData; //---接收数据事件 LogInfoDisplay += info; //--------------消息事件 this.info.msgType = nameClient; //---log消息类型 } #endregion #region 断开连接 /*关闭客户端*/ /// <summary> /// 断开连接 /// </summary> public void Disconnect() { try { if (ClientSocket != null) { if (ClientSocket.Connected == true) { ClientSocket.Close(); ClientSocket.Dispose(); info.msg = "Socket连接关闭成功"; if (LogInfoDisplay != null) //------判断委托不为空时执行委托 LogInfoDisplay(info); } else { info.msg = "Socket连接不存在!"; if (LogInfoDisplay != null) //------判断委托不为空时执行委托 LogInfoDisplay(info); } } } catch { } try { if (receiveTh != null) { if (receiveTh.IsAlive == true) { ClientSocket.Close(); receiveTh.Abort(); //-----------------------接收socket线程关闭 receiveTh.DisableComObjectEagerCleanup(); info.msg = "客户端关闭成功!"; if (LogInfoDisplay != null) //------判断委托不为空时执行委托 LogInfoDisplay(info); } else { info.msg = "客户端不存在!"; if (LogInfoDisplay != null) //------判断委托不为空时执行委托 LogInfoDisplay(info); } } } catch { } Thread.Sleep(100); } #endregion #region 连接的Socket /*连接的Socket*/ /// <summary> /// 连接的Socket /// </summary> /// <param name="IP">IP地址</param> /// <param name="Port">端口号</param> public void Connection(string IP, string Port) { try { IPAddress ip = IPAddress.Parse(IP.Trim()); IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(Port.Trim())); if (ClientSocket != null) { ClientSocket.Dispose(); } Disconnect(); ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); ClientSocket.Connect(point); info.msgType = nameClient; info.msg = "连接成功"; if (LogInfoDisplay != null) //------判断委托不为空时执行委托 LogInfoDisplay(info); /*开启一个新线程负责不停的接收服务器发过来的数据*/ if (receiveTh == null) { receiveTh = new Thread(Receive); //-----------------------接收socket线程 receiveTh.IsBackground = true; receiveTh.Start(); } else { if (receiveTh.IsAlive != true) { receiveTh = new Thread(Receive); //-----------------------接收socket线程 receiveTh.IsBackground = true; receiveTh.Start(); } } } catch { } } #endregion #region 地址解析 /// <summary> /// 地址解析 /// </summary> /// <param name="addr">地址</param> /// <returns>地址数组</returns> private byte[] AddrResolver(string addr) { /*ModubusTCP读取命令固定格式 addrBuffer[0]-----地址H addrBuffer[1]-----地址L */ char[] addrChar = addr.ToArray(); string addrStr = ""; byte[] addrBuffer = new byte[5]; for (int i = 1; i < addrChar.Length; i++) { addrStr += addrChar[i]; } int addrInt = int.Parse(addrStr); string addrStr2 = addrInt.ToString("x"); string addrStr3 = ""; switch (addrStr2.Length) { case 1: addrStr3 = "0" + "0" + "0" + addrStr2; break; case 2: addrStr3 = "0" + "0" + addrStr2; break; case 3: addrStr3 = "0" + addrStr2; break; case 4: addrStr3 = addrStr2; break; } char[] addrChar2 = addrStr3.ToArray(); addrBuffer[0] = byte.Parse(addrChar2[0].ToString() + addrChar2[1].ToString(), System.Globalization.NumberStyles.HexNumber); addrBuffer[1] = byte.Parse(addrChar2[2].ToString() + addrChar2[3].ToString(), System.Globalization.NumberStyles.HexNumber); return addrBuffer; } #endregion #region 读取线圈寄存器(M寄存器) /// <summary> /// 读取线圈寄存器 /// </summary> /// <param name="ID">客户端ID</param> /// <param name="addr">地址</param> /// <param name="length">长度</param> /// <returns>值</returns> public bool[] ReadCoils(short ID, string addr, int length) { #region 读取线圈寄存器指令 /*BIN指令*/ /*读取线圈寄存器指令*/ //byte[] buffer = new byte[255]; //buffer[0] = 0x00; //----事务处理标识H--固定值0x00 //buffer[1] = 0x01; //----事务处理标识L--固定值0x00 //buffer[2] = 0x00; //----协议标识H--固定值0x00 //buffer[3] = 0x00; //----协议标识L--固定值0x00 //buffer[4] = 0x00; //----长度H //buffer[5] = 0x06; //----长度L //buffer[6] = 0x01; //----单位标识 //buffer[7] = 0x03; //----功能码 //buffer[8] = 0x00; //----线圈寄存器起始地址H //buffer[9] = 0x01; //----线圈寄存器起始地址L //buffer[10] = 0x00; //---线圈寄存器个数H //buffer[11] = 0x01; //---线圈寄存器个数L #endregion #region 读取线圈寄存器指令反馈 /*读取线圈寄存器指令反馈*/ //byte[] buffer = new byte[255]; //buffer[0] = 0x00; //----事务处理标识H--固定值0x00 //buffer[1] = 0x00; //----事务处理标识L--固定值0x00 //buffer[2] = 0x00; //----协议标识H--固定值0x00 //buffer[3] = 0x00; //----协议标识L--固定值0x00 //buffer[4] = 0x00; //----长度H //buffer[5] = 0x06; //----长度L //buffer[6] = 0x01; //----单位标识 //buffer[7] = 0x06; //----功能码 //buffer[8] = 0x01; //----线圈寄存器字节数:后面的数据字节数(例:线圈字节数=3时,数据有3个字节) //buffer[9] = 0x01; //----数据 #endregion bool[] result = new bool[length]; //--------------------读取线圈寄存器返回值 byte[] addrByte = AddrResolver(addr); //----------------线圈寄存器首地址数组 byte[] lenghtBuffer = WriteDataResolver(length); //-----线圈寄存器个数数组 #region 发送指令 /*BIN指令*/ /*读线圈寄存器指令*/ buffer[0] = 0x00; //----事务处理标识H--固定值0x00 buffer[1] = 0x01; //----事务处理标识L--固定值0x00 buffer[2] = 0x00; //----协议标识H--固定值0x00 buffer[3] = 0x00; //----协议标识L--固定值0x00 buffer[4] = 0x00; //----长度H buffer[5] = 0x06; //----长度L buffer[6] = (byte)ID; //----单位标识--一般为0x01 buffer[7] = Convert.ToByte((short)Comand.读线圈寄存器); //----功能码 buffer[8] = addrByte[0]; //--------起始线圈寄存器地址H buffer[9] = addrByte[1]; //--------起始线圈寄存器地址L buffer[10] = lenghtBuffer[0]; //---线圈寄存器个数H buffer[11] = lenghtBuffer[1]; //---线圈寄存器个数L #endregion #region 发送 try { ClientSocket.Send(buffer, 6 + buffer[5], SocketFlags.None); //----发送 } catch { } #endregion Thread.Sleep(100); #region 返回数据解析 int j = 1; int m = 1; try { for (int i = 0; i < length; i++) { if (i % 8 == 0) { j = 1; m = 1; } if (i % 8 == 0) { m = 1 * j; j = j * 10; } else { m = 2 * m; } result[i] = (data[i / 8] & m) == m ? true : false; } } catch { } #endregion return result; } #endregion #region 读取输入状态 /// <summary> /// 读取输入状态 /// </summary> /// <param name="ID">客户端ID</param> /// <param name="addr">地址</param> /// <param name="length">长度</param> /// <returns>值</returns> public bool[] ReadInput(short ID, string addr, int length) { #region 读取输入状态指令 /*BIN指令*/ /*读取输入状态指令*/ //byte[] buffer = new byte[255]; //buffer[0] = 0x00; //----事务处理标识H--固定值0x00 //buffer[1] = 0x01; //----事务处理标识L--固定值0x00 //buffer[2] = 0x00; //----协议标识H--固定值0x00 //buffer[3] = 0x00; //----协议标识L--固定值0x00 //buffer[4] = 0x00; //----长度H //buffer[5] = 0x06; //----长度L //buffer[6] = 0x01; //----单位标识 //buffer[7] = 0x03; //----功能码 //buffer[8] = 0x00; //----输入状态起始地址H //buffer[9] = 0x01; //----输入状态起始地址L //buffer[10] = 0x00; //---读取个数H //buffer[11] = 0x01; //---读取个数L #endregion #region 读取输入状态指令反馈 /*读取输入状态指令反馈*/ //byte[] buffer = new byte[255]; //buffer[0] = 0x00; //----事务处理标识H--固定值0x00 //buffer[1] = 0x00; //----事务处理标识L--固定值0x00 //buffer[2] = 0x00; //----协议标识H--固定值0x00 //buffer[3] = 0x00; //----协议标识L--固定值0x00 //buffer[4] = 0x00; //----长度H //buffer[5] = 0x06; //----长度L //buffer[6] = 0x01; //----单位标识 //buffer[7] = 0x06; //----功能码 //buffer[8] = 0x01; //----字节数:后面的数据字节数(例:线圈字节数=3时,数据有3个字节) //buffer[9] = 0x01; //----输入状态 #endregion byte count = length % 8 == 0 ? (byte)(length / 8) : (byte)(length / 8 + 1); //----字节长度 bool[] result = new bool[length]; //---------------------读取输入状态返回值 byte[] addrByte = AddrResolver(addr); //----------------输入状态起始地址数组 byte[] lenghtBuffer = WriteDataResolver(length); //-----输入状态个数数组 #region 发送指令 /*BIN指令*/ /*读输入寄存器指令*/ buffer[0] = 0x00; //----事务处理标识H--固定值0x00 buffer[1] = 0x01; //----事务处理标识L--固定值0x00 buffer[2] = 0x00; //----协议标识H--固定值0x00 buffer[3] = 0x00; //----协议标识L--固定值0x00 buffer[4] = 0x00; //----长度H buffer[5] = 0x06; //----长度L buffer[6] = (byte)ID; //----单位标识--一般为0x01 buffer[7] = Convert.ToByte((short)Comand.读输入状态); //----功能码 buffer[8] = addrByte[0]; //----输入状态起始地址H buffer[9] = addrByte[1]; //----输入状态起始地址L buffer[10] = lenghtBuffer[0]; //---读取个数H buffer[11] = lenghtBuffer[1]; //---读取个数L #endregion #region 发送 try { ClientSocket.Send(buffer, 6 + buffer[5], SocketFlags.None); //----发送 } catch { } #endregion Thread.Sleep(100); #region 返回数据解析 int j = 1; int m = 1; try { for (int i = 0; i < length; i++) { if (i % 8 == 0) { j = 1; m = 1; } if (i % 8 == 0) { m = 1 * j; j = j * 10; } else { m = 2 * m; } result[i] = (data[i / 8] & m) == m ? true : false; } } catch { } #endregion return result; } #endregion #region 读取保持寄存器(D寄存器) /// <summary> /// 读取类型 /// </summary> public enum ReadTypeEnum : short { 字 = 1, 双字 = 2 } /// <summary> /// 读取保持寄存器 /// </summary> /// <param name="ID">客户端ID</param> /// <param name="addr">地址</param> /// <param name="length">长度</param> /// <param name="type">类型</param> /// <returns>值</returns> public long[] ReadHoldingRegister(short ID, string addr, int length, ReadTypeEnum type = ReadTypeEnum.字) { #region 读保持寄存器反馈指令 /*BIN指令*/ /*读保持寄存器指令*/ //byte[] buffer = new byte[255]; //buffer[0] = 0x00; //----事务处理标识H--固定值0x00 //buffer[1] = 0x01; //----事务处理标识L--固定值0x00 //buffer[2] = 0x00; //----协议标识H--固定值0x00 //buffer[3] = 0x00; //----协议标识L--固定值0x00 //buffer[4] = 0x00; //----长度H //buffer[5] = 0x06; //----长度L //buffer[6] = 0x01; //----单位标识 //buffer[7] = 0x03; //----功能码 //buffer[8] = 0x00; //----寄存器起始地址H //buffer[9] = 0x01; //----寄存器起始地址L //buffer[10] = 0x00; //---寄存器个数H //buffer[11] = 0x01; //---寄存器个数L #endregion #region 读保持寄存器反馈指令反馈 /*读保持寄存器反馈指令反馈*/ //byte[] buffer = new byte[255]; //buffer[0] = 0x00; //----事务处理标识H--固定值0x00 //buffer[1] = 0x00; //----事务处理标识L--固定值0x00 //buffer[2] = 0x00; //----协议标识H--固定值0x00 //buffer[3] = 0x00; //----协议标识L--固定值0x00 //buffer[4] = 0x00; //----长度H //buffer[5] = 0x06; //----长度L //buffer[6] = 0x01; //----单位标识 //buffer[7] = 0x06; //----功能码 //buffer[8] = 0x01; //----寄存器个数 //buffer[9] = 0x01; //----寄存器数据H_每个数2个字节 //buffer[10] = 0x01; //---寄存器数据L_每个数2个字节 #endregion startTime = DateTime.Now; long[] result = new long[length]; //----------------------读取寄存器返回值 byte[] addrByte = AddrResolver(addr); //------------------------------寄存器首地址数组 byte[] lenghtBuffer = WriteDataResolver(length * (short)type); //-----寄存器个数数组 #region 发送指令 /*BIN指令*/ /*读保持寄存器指令*/ buffer[0] = 0x00; //----事务处理标识H--固定值0x00 buffer[1] = 0x01; //----事务处理标识L--固定值0x00 buffer[2] = 0x00; //----协议标识H--固定值0x00 buffer[3] = 0x00; //----协议标识L--固定值0x00 buffer[4] = 0x00; //----长度H buffer[5] = 0x06; //----长度L buffer[6] = (byte)ID; //----单位标识--一般为0x01 buffer[7] = Convert.ToByte((short)Comand.读保存寄存器); //----功能码 buffer[8] = addrByte[0]; //----起始寄存器地址H buffer[9] = addrByte[1]; //----起始寄存器地址L buffer[10] = lenghtBuffer[0]; //---寄存器个数H buffer[11] = lenghtBuffer[1]; //---寄存器个数L #endregion #region 发送 try { ClientSocket.Send(buffer, 6 + buffer[5], SocketFlags.None); //----发送 } catch { } #endregion stopTime1 = DateTime.Now; info.msg = "发送时间(毫秒):" + stopTime1.Subtract(startTime).Milliseconds; if (LogInfoDisplay != null) //------判断委托不为空时执行委托 LogInfoDisplay(info); Thread.Sleep(5); #region 返回数据解析 try { if (type == ReadTypeEnum.字) { for (int i = 0; i < 2 * length; i = i + 2) { result[i / 2] = data[i] * 256 + data[i + 1]; //负数求补码 if (result[i] > 0x8000) { result[i] = GetComplementer(result[i], 2); result[i] = -result[i]; } } } if (type == ReadTypeEnum.双字) { for (int i = 0; i < 4 * length; i = i + 4) { result[i / 4] = data[i] * 256 + data[i + 1] + data[i + 2] * 256 * 256 * 256 + data[i + 3] * 256 * 256; //负数求补码 if (result[i] > 0x80000000) { result[i] = GetComplementer(result[i], 4); result[i] = -result[i]; } } } } catch { } #endregion stopTime = DateTime.Now; info.msg = "读取总时间(毫秒):" + stopTime.Subtract(startTime).Milliseconds; if (LogInfoDisplay != null) //------判断委托不为空时执行委托 LogInfoDisplay(info); return result; } #endregion #region 读取输入寄存器 /// <summary> /// 读取输入寄存器 /// </summary> /// <param name="ID">客户端ID</param> /// <param name="addr">地址</param> /// <param name="length">长度</param> /// <param name="type">类型</param> /// <returns>值</returns> public long[] ReadInputRegister(short ID, string addr, int length, ReadTypeEnum type = ReadTypeEnum.字) { #region 读取输入寄存器指令 /*BIN指令*/ /*读取输入寄存器指令*/ //byte[] buffer = new byte[255]; //buffer[0] = 0x00; //----事务处理标识H--固定值0x00 //buffer[1] = 0x01; //----事务处理标识L--固定值0x00 //buffer[2] = 0x00; //----协议标识H--固定值0x00 //buffer[3] = 0x00; //----协议标识L--固定值0x00 //buffer[4] = 0x00; //----长度H //buffer[5] = 0x06; //----长度L //buffer[6] = 0x01; //----单位标识 //buffer[7] = 0x03; //----功能码 //buffer[8] = 0x00; //----输入寄存器起始地址H //buffer[9] = 0x01; //----输入寄存器起始地址L //buffer[10] = 0x00; //---读取个数H //buffer[11] = 0x01; //---读取个数L #endregion #region 读取输入寄存器指令反馈 /*读取输入寄存器指令反馈*/ //byte[] buffer = new byte[255]; //buffer[0] = 0x00; //----事务处理标识H--固定值0x00 //buffer[1] = 0x00; //----事务处理标识L--固定值0x00 //buffer[2] = 0x00; //----协议标识H--固定值0x00 //buffer[3] = 0x00; //----协议标识L--固定值0x00 //buffer[4] = 0x00; //----长度H //buffer[5] = 0x06; //----长度L //buffer[6] = 0x01; //----单位标识 //buffer[7] = 0x06; //----功能码 //buffer[8] = 0x01; //----字节数:后面的数据字节数(例:线圈字节数=3时,数据有3个字节) //buffer[9] = 0x01; //----输入状态 #endregion long[] result = new long[length]; //--------------------读取输入寄存器返回值 byte[] addrByte = AddrResolver(addr); //----------------输入寄存器起始地址数组 byte[] lenghtBuffer = WriteDataResolver(length * (short)type); //-----输入寄存器个数数组 #region 发送指令 /*BIN指令*/ /*读输入寄存器指令*/ buffer[0] = 0x00; //----事务处理标识H--固定值0x00 buffer[1] = 0x01; //----事务处理标识L--固定值0x00 buffer[2] = 0x00; //----协议标识H--固定值0x00 buffer[3] = 0x00; //----协议标识L--固定值0x00 buffer[4] = 0x00; //----长度H buffer[5] = 0x06; //----长度L buffer[6] = (byte)ID; //----单位标识--一般为0x01 buffer[7] = Convert.ToByte((short)Comand.读输入寄存器); //----功能码 buffer[8] = addrByte[0]; //----输入寄存器起始地址H buffer[9] = addrByte[1]; //----输入寄存器起始地址L buffer[10] = lenghtBuffer[0]; //---读取个数H buffer[11] = lenghtBuffer[1]; //---读取个数L #endregion #region 发送 try { ClientSocket.Send(buffer, 6 + buffer[5], SocketFlags.None); //----发送 } catch { } #endregion Thread.Sleep(100); #region 返回数据解析 try { if (type == ReadTypeEnum.字) { for (int i = 0; i < 2 * length; i = i + 2) { result[i / 2] = data[i] * 256 + data[i + 1]; //负数求补码 if (result[i] > 0x8000) { result[i] = GetComplementer(result[i], 2); result[i] = -result[i]; } } } if (type == ReadTypeEnum.双字) { for (int i = 0; i < 4 * length; i = i + 4) { result[i / 4] = data[i] * 256 + data[i + 1] + data[i + 2] * 256 * 256 * 256 + data[i + 3] * 256 * 256; //负数求补码 if (result[i] > 0x80000000) { result[i] = GetComplementer(result[i], 4); result[i] = -result[i]; } } } } catch { } #endregion return result; } #endregion #region 写入单个线圈寄存器值(M寄存器) /// <summary> /// 写入单个线圈寄存器值 /// </summary> /// <param name="ID">客户端ID</param> /// <param name="addr">地址</param> /// <param name="value">值</param> public void WriteSingleCoils(short ID, string addr, string value) { #region 写入单个线圈寄存器值 /*BIN指令*/ /*写入单个线圈寄存器值*/ //byte[] buffer = new byte[255]; //buffer[0] = 0x00; //----事务处理标识H--固定值0x00 //buffer[1] = 0x01; //----事务处理标识L--固定值0x00 //buffer[2] = 0x00; //----协议标识H--固定值0x00 //buffer[3] = 0x00; //----协议标识L--固定值0x00 //buffer[4] = 0x00; //----长度H //buffer[5] = 0x06; //----长度L //buffer[6] = 0x01; //----单位标识 //buffer[7] = 0x03; //----功能码 //buffer[8] = 0x00; //----线圈寄存器地址H //buffer[9] = 0x01; //----线圈寄存器地址L //buffer[10] = 0x00; //---设置值H //buffer[11] = 0x01; //---设置值L #endregion #region 写入单个线圈寄存器反馈 /*写入单个线圈寄存器反馈*/ //byte[] buffer = new byte[255]; //buffer[0] = 0x00; //----事务处理标识H--固定值0x00 //buffer[1] = 0x00; //----事务处理标识L--固定值0x00 //buffer[2] = 0x00; //----协议标识H--固定值0x00 //buffer[3] = 0x00; //----协议标识L--固定值0x00 //buffer[4] = 0x00; //----长度H //buffer[5] = 0x06; //----长度L //buffer[6] = 0x01; //----单位标识 //buffer[7] = 0x06; //----功能码 //buffer[8] = 0x01; //----线圈寄存器地址H //buffer[9] = 0x01; //----线圈寄存器地址L //buffer[10] = 0x00; //---设置值H //buffer[11] = 0x01; //---设置值L #endregion byte[] addrByte = AddrResolver(addr); //-----------线圈寄存器起始地址数组 byte[] data = new byte[2]; //----------------------写入数据 #region 写入数据 if (value == "0" || value == "false") { data[0] = 0x00; data[1] = 0x00; } if (value != "0" || value == "true") { data[0] = 0xff; data[1] = 0x00; } #endregion #region 发送指令 /*BIN指令*/ /*写单个线圈寄存器指令*/ buffer[0] = 0x00; //----事务处理标识H--固定值0x00 buffer[1] = 0x01; //----事务处理标识L--固定值0x00 buffer[2] = 0x00; //----协议标识H--固定值0x00 buffer[3] = 0x00; //----协议标识L--固定值0x00 buffer[4] = 0x00; //----长度H buffer[5] = 0x06; //----长度L buffer[6] = (byte)ID; //----单位标识--一般为0x01 buffer[7] = Convert.ToByte((short)Comand.写单个线圈寄存器); //----功能码 buffer[8] = addrByte[0]; //----起始线圈寄存器地址H buffer[9] = addrByte[1]; //----起始线圈寄存器地址L buffer[10] = data[0]; //---设定值H buffer[11] = data[1]; //---设定值L #endregion #region 发送 try { ClientSocket.Send(buffer, 6 + buffer[5], SocketFlags.None); //----发送 } catch { } #endregion } #endregion #region 写入单个保持寄存器值(D寄存器) /// <summary> /// 写入单个保持寄存器值 /// </summary> /// <param name="ID">客户端ID</param> /// <param name="addr">地址</param> /// <param name="value">值</param> public void WriteSingleRegister(short ID, string addr, string value) { #region 写入单个保持寄存器值 /*BIN指令*/ /*写入单个保持寄存器值*/ //byte[] buffer = new byte[255]; //buffer[0] = 0x00; //----事务处理标识H--固定值0x00 //buffer[1] = 0x01; //----事务处理标识L--固定值0x00 //buffer[2] = 0x00; //----协议标识H--固定值0x00 //buffer[3] = 0x00; //----协议标识L--固定值0x00 //buffer[4] = 0x00; //----长度H //buffer[5] = 0x06; //----长度L //buffer[6] = 0x01; //----单位标识 //buffer[7] = 0x03; //----功能码 //buffer[8] = 0x00; //----寄存器地址H //buffer[9] = 0x01; //----寄存器地址L //buffer[10] = 0x00; //---设置值H //buffer[11] = 0x01; //---设置值L #endregion #region 写入单个保持寄存器反馈 /*写入单个保持寄存器反馈*/ //byte[] buffer = new byte[255]; //buffer[0] = 0x00; //----事务处理标识H--固定值0x00 //buffer[1] = 0x00; //----事务处理标识L--固定值0x00 //buffer[2] = 0x00; //----协议标识H--固定值0x00 //buffer[3] = 0x00; //----协议标识L--固定值0x00 //buffer[4] = 0x00; //----长度H //buffer[5] = 0x06; //----长度L //buffer[6] = 0x01; //----单位标识 //buffer[7] = 0x06; //----功能码 //buffer[8] = 0x01; //----寄存器地址H //buffer[9] = 0x01; //----寄存器地址L //buffer[10] = 0x00; //---设置值H //buffer[11] = 0x01; //---设置值L #endregion byte[] addrByte = AddrResolver(addr); //-----------线圈地址数组 byte[] data = WriteDataResolver(value, 2); //---------写入数据 #region 发送指令 /*BIN指令*/ /*写单个保持寄存器指令*/ buffer[0] = 0x00; //----事务处理标识H--固定值0x00 buffer[1] = 0x01; //----事务处理标识L--固定值0x00 buffer[2] = 0x00; //----协议标识H--固定值0x00 buffer[3] = 0x00; //----协议标识L--固定值0x00 buffer[4] = 0x00; //----长度H buffer[5] = 0x06; //----长度L buffer[6] = (byte)ID; //----单位标识--一般为0x01 buffer[7] = Convert.ToByte((short)Comand.写单个保存寄存器); //----功能码 buffer[8] = addrByte[0]; //----起始线圈地址H buffer[9] = addrByte[1]; //----起始线圈地址L buffer[10] = data[0]; //---设置值H buffer[11] = data[1]; //---设置值L #endregion #region 发送 try { ClientSocket.Send(buffer, 6 + buffer[5], SocketFlags.None); //----发送 } catch { } #endregion } #endregion #region 写入多个线圈寄存器值(M寄存器) /// <summary> /// 写入多个线圈寄存器值 /// </summary> /// <param name="ID">客户端ID</param> /// <param name="addr">地址</param> /// <param name="length">长度</param> /// <param name="value">值</param> public void WriteMultipleleCoils(short ID, string addr, int length, int value) { #region 写入多个线圈值 /*BIN指令*/ /*写入多个线圈寄存器值*/ //byte[] buffer = new byte[255]; //buffer[0] = 0x00; //----事务处理标识H--固定值0x00 //buffer[1] = 0x01; //----事务处理标识L--固定值0x00 //buffer[2] = 0x00; //----协议标识H--固定值0x00 //buffer[3] = 0x00; //----协议标识L--固定值0x00 //buffer[4] = 0x00; //----长度H //buffer[5] = 0x06; //----长度L //buffer[6] = 0x01; //----单位标识 //buffer[7] = 0x03; //----功能码 //buffer[8] = 0x00; //----线圈寄存器起始地址H //buffer[9] = 0x01; //----线圈寄存器起始地址L //buffer[10] = 0x00; //---设置长度H //buffer[11] = 0x01; //---设置长度L //buffer[12] = 0x00; //---字节长度 //buffer[13] = 0x01; //---设置值1H //buffer[14] = 0x00; //---设置值1L //buffer[15] = 0x01; //---设置值2H //buffer[16] = 0x00; //---设置值2L #endregion #region 写入多个线圈寄存器反馈 /*写入多个线圈寄存器反馈*/ //byte[] buffer = new byte[255]; //buffer[0] = 0x00; //----事务处理标识H--固定值0x00 //buffer[1] = 0x00; //----事务处理标识L--固定值0x00 //buffer[2] = 0x00; //----协议标识H--固定值0x00 //buffer[3] = 0x00; //----协议标识L--固定值0x00 //buffer[4] = 0x00; //----长度H //buffer[5] = 0x06; //----长度L //buffer[6] = 0x01; //----单位标识 //buffer[7] = 0x06; //----功能码 //buffer[8] = 0x01; //----线圈寄存器起始地址H //buffer[9] = 0x01; //----线圈寄存器起始地址L //buffer[10] = 0x00; //---设置长度H //buffer[11] = 0x01; //---设置长度L #endregion byte[] addrByte = AddrResolver(addr); //--------------线圈寄存器起始地址数组 byte[] lengthByte = WriteDataResolver(length); //-----设置长度数组 byte count = length % 8 == 0 ? (byte)(length / 8) : (byte)(length / 8 + 1); //----字节长度 byte[] data = WriteDataResolver(value, count); //---------------------------------写入数据 #region 发送指令 /*BIN指令*/ /*写多个线圈寄存器指令*/ buffer[0] = 0x00; //----事务处理标识H--固定值0x00 buffer[1] = 0x01; //----事务处理标识L--固定值0x00 buffer[2] = 0x00; //----协议标识H--固定值0x00 buffer[3] = 0x00; //----协议标识L--固定值0x00 buffer[4] = 0x00; //----长度H buffer[5] = (byte)(7 + count); //----长度L buffer[6] = (byte)ID; //----单位标识--一般为0x01 buffer[7] = Convert.ToByte((short)Comand.写多个线圈寄存器); //----功能码 buffer[8] = addrByte[0]; //----线圈寄存器起始地址H buffer[9] = addrByte[1]; //----线圈寄存器起始地址L buffer[10] = lengthByte[0]; //---设置长度H buffer[11] = lengthByte[1]; //---设置长度L buffer[12] = count; //---字节长度 for (int i = 0; i < data.Length; i++) { buffer[13 + i] = data[i]; //------设置值 } #endregion #region 发送 try { ClientSocket.Send(buffer, 6 + buffer[5], SocketFlags.None); //----发送 } catch { } #endregion } #endregion #region 写入多个保持寄存器值(D寄存器) /// <summary> /// 写入多个保持寄存器值 /// </summary> /// <param name="ID">客户端ID</param> /// <param name="addr">地址</param> /// <param name="length">长度</param> /// <param name="value">值</param> public void WriteMultipleRegister(short ID, string addr, int length, string value) { #region 写入多个保持寄存器值 /*BIN指令*/ /*写入多个保持寄存器值*/ //byte[] buffer = new byte[255]; //buffer[0] = 0x00; //----事务处理标识H--固定值0x00 //buffer[1] = 0x01; //----事务处理标识L--固定值0x00 //buffer[2] = 0x00; //----协议标识H--固定值0x00 //buffer[3] = 0x00; //----协议标识L--固定值0x00 //buffer[4] = 0x00; //----长度H //buffer[5] = 0x06; //----长度L //buffer[6] = 0x01; //----单位标识 //buffer[7] = 0x03; //----功能码 //buffer[8] = 0x00; //----寄存器起始地址H //buffer[9] = 0x01; //----寄存器起始地址L //buffer[10] = 0x00; //---设置长度H //buffer[11] = 0x01; //---设置长度L //buffer[12] = 0x01; //---字节个数 //buffer[13] = 0x01; //---设置值1H //buffer[14] = 0x01; //---设置值1L //buffer[15] = 0x01; //---设置值2H //buffer[16] = 0x01; //---设置值2L #endregion #region 写入多个保持寄存器反馈 /*写入多个保持寄存器反馈*/ //byte[] buffer = new byte[255]; //buffer[0] = 0x00; //----事务处理标识H--固定值0x00 //buffer[1] = 0x00; //----事务处理标识L--固定值0x00 //buffer[2] = 0x00; //----协议标识H--固定值0x00 //buffer[3] = 0x00; //----协议标识L--固定值0x00 //buffer[4] = 0x00; //----长度H //buffer[5] = 0x06; //----长度L //buffer[6] = 0x01; //----单位标识 //buffer[7] = 0x06; //----功能码 //buffer[8] = 0x01; //----寄存器起始地址H //buffer[9] = 0x01; //----寄存器起始地址L //buffer[10] = 0x00; //---设置长度H //buffer[11] = 0x01; //---设置长度L #endregion byte[] addrByte = AddrResolver(addr); //----------------寄存器起始地址数组 byte[] lenghtBuffer = WriteDataResolver(length); //-----寄存器个数数组 byte[] data = WriteDataResolver(value, 2 * length); //--------------写入数据 #region 发送指令 /*BIN指令*/ /*写多个保持寄存器指令*/ buffer[0] = 0x00; //----事务处理标识H--固定值0x00 buffer[1] = 0x01; //----事务处理标识L--固定值0x00 buffer[2] = 0x00; //----协议标识H--固定值0x00 buffer[3] = 0x00; //----协议标识L--固定值0x00 buffer[4] = 0x00; //----长度H buffer[5] = (byte)(7 + 2 * length); //----长度L buffer[6] = (byte)ID; //----单位标识--一般为0x01 buffer[7] = Convert.ToByte((short)Comand.写多个保持寄存器); //----功能码 buffer[8] = addrByte[0]; //----寄存器首地址H buffer[9] = addrByte[1]; //----寄存器首地址L buffer[10] = lenghtBuffer[0]; //---设定长度H buffer[11] = lenghtBuffer[1]; //---设定长度L buffer[12] = (byte)(2 * length); //---字节个数 for (int i = 0; i < data.Length; i++) { buffer[13 + i] = data[i]; //------设置值 } #endregion #region 发送 try { ClientSocket.Send(buffer, 6 + buffer[5], SocketFlags.None); //----发送 } catch { } #endregion } #endregion #region 写入数据解析 /// <summary> /// 写入数据解析 /// </summary> /// <param name="data">字符数据</param> /// <returns>返回byte数组</returns> private byte[] WriteDataResolver(string data, int length) { #region 以前公式-屏蔽 //byte[] dataBuffer = new byte[2]; //int data1, data2; //long data_long = Convert.ToInt64(data); //data1 = (int)data_long % 256; //data2 = (int)data_long / 256; //if (data2 > 255) // data2 = data2 % 255; //dataBuffer[0] = Convert.ToByte(data2); //dataBuffer[1] = Convert.ToByte(data1); //return dataBuffer; #endregion byte[] dataBuffer = new byte[length]; long data_long = Convert.ToInt64(data); if (data_long < 0) { data_long = Math.Abs(data_long); data_long = GetComplementer(data_long, length); } for (int i = 0; i < length; i++) { #region 以前公式 //dataBuffer[length - 1 - i] = Convert.ToByte(data_long % 256); //---倒序(低位在前,高位在后) #endregion dataBuffer[i] = Convert.ToByte(data_long % 256); //---正序(高位在前,低位在后) data_long = data_long / 256; } #region 高底位互换 byte buffer = 0; for (int i = 0; i < length / 2; i++) { buffer = dataBuffer[2 * i]; dataBuffer[2 * i] = dataBuffer[2 * i + 1]; dataBuffer[2 * i + 1] = buffer; } #endregion return dataBuffer; } /// <summary> /// 写入数据解析 /// </summary> /// <param name="data">整数数据</param> /// <param name="length">字节长度</param> /// <returns>返回byte数组</returns> private byte[] WriteDataResolver(int data, int length = 2) { byte[] dataBuffer = new byte[length]; long data_long = Convert.ToInt64(data); if (data_long < 0) { data_long = Math.Abs(data_long); data_long = GetComplementer(data_long, length); } for (int i = 0; i < length; i++) { dataBuffer[length - 1 - i] = Convert.ToByte(data_long % 256); data_long = data_long / 256; } return dataBuffer; } #endregion #region 负数求补码 /// <summary> /// 负数求补码long类型 /// </summary> /// <param name="data">数据</param> /// <param name="length">长度</param> /// <returns></returns> private long GetComplementer(long data, int length) { long lData = 0; switch (length) { case 2: //------字 lData = data ^ 0xFFFF; lData++; break; case 4: //------双字 lData = data ^ 0xFFFFFFFF; lData++; break; } return lData; } #endregion #region ModubusTCP协议数据接收--开启一个新线程负责不停的接收服务器发过来的数据 /// <summary> /// 数据接收 /// </summary> private void Receive() { while (true) { try { byte[] buffer = new byte[255]; int r = ClientSocket.Receive(buffer); stopTime2 = DateTime.Now; info.msg = "接收时间(毫秒):" + stopTime2.Subtract(stopTime1).Milliseconds; if (LogInfoDisplay != null) //------判断委托不为空时执行委托 LogInfoDisplay(info); data = ReceiveResolver(buffer); string newBuffer = ""; for (int i = 0; i < r; i++) { newBuffer += buffer[i].ToString("x") + " "; } info.msg = "反馈数据:" + newBuffer; if (LogInfoDisplay != null) //------判断委托不为空时执行委托 LogInfoDisplay(info); stopTime3 = DateTime.Now; info.msg = "解析时间(毫秒):" + stopTime3.Subtract(stopTime2).Milliseconds; if (LogInfoDisplay != null) //------判断委托不为空时执行委托 LogInfoDisplay(info); Disconnect(); //------------断开连接 //if (buffer[8] <= 2) /*判断数据读取命令或写入反馈*/ //{ // /*数据读取命令*/ // string dataStr = buffer[9].ToString("x") + buffer[10].ToString("x"); // state = "16进制:" + dataStr + ""; // Infomation(state); /*回调方法---状态显示*/ // int dataInt = int.Parse(dataStr, System.Globalization.NumberStyles.HexNumber); // state = "10进制:" + dataInt + ""; // Infomation(state); /*回调方法---状态显示*/ //} //else //{ // /*写入反馈*/ // state = "反馈:" + newBuffer + ""; // Infomation(state); /*回调方法---状态显示*/ //} //Thread.Sleep(5); } catch (Exception e) { //Infomation(e.ToString()); /*回调方法---状态显示*/ } } } #endregion #region 接收数据解析 /// <summary> /// 接收数据解析 /// </summary> /// <param name="buffer">接收到byte数组</param> /// <returns>byte数组</returns> public byte[] ReceiveResolver(byte[] buffer) { byte[] dataBuffer = null; int length = 1; if (buffer[5] > 3) //---------------数据长度 { length = (int)buffer[8]; //-----字节数 dataBuffer = new byte[length]; switch (buffer[7]) //-----------功能码 { case (byte)Comand.读线圈寄存器: //-------------功能:0x01 for (int i = 0; i < length; i++) { dataBuffer[i] = buffer[9 + i]; } break; case (byte)Comand.读输入状态: //-------------功能:0x02 for (int i = 0; i < length; i++) { dataBuffer[i] = buffer[9 + i]; } break; case (byte)Comand.读保存寄存器: //-----------功能:0x03 for (int i = 0; i < length; i++) { dataBuffer[i] = buffer[9 + i]; } break; case (byte)Comand.读输入寄存器: //-----------功能:0x04 for (int i = 0; i < length; i++) { dataBuffer[i] = buffer[9 + i]; } break; } } return dataBuffer; } #endregion } #endregion
最新发布
10-08
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值