package Client;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.nio.channels.IllegalBlockingModeException;
import Config.ParameterCfg;
import ErrorExcp.ErrorExcp;
import Log.Log;
import Msg.Msg.Msg;
import MsgCfg.MsgGlobalInfo;
/**
*
* @author xiehui 通信类,数据的发送与接受
*
*/
public class Client {
/**
* 负责数据发送与接受的套接字
*/
public Socket ncpClient;
/**
* socket读取数据管道
*/
public OutputStream writeIO;
/**
* socket写数据管道
*/
public InputStream receiveIO;
/**
*日志记录
*/
public Log log;
/**
* 是否做了资源释放,避免二次释放引起bug,默认为假
*/
public boolean isCloseDeal = false;
/**
* 在套接字上获取的报文信息
*/
public MsgInfo msgInfo;
/**
* Client()函数为构造函数
*
* @param acccpetSocket
* :为服务器投递过来的套接字<br>
*
* log:为传递的日志对象,方便在通信的过程中将状态记录下来
*
* @return 没有返回值的内容
*
* @exception exceptions
* 没有异常被抛出
*/
public Client(Socket acccpetSocket, Log log) {
/**
* 套接字本地创建的,发起方是农产品前置机
*/
this.ncpClient = acccpetSocket;
this.log = log;
msgInfo = new MsgInfo();
/**
* 将发起的IP地址写入日志
*/
log.add(acccpetSocket.getRemoteSocketAddress());
}
/**
* 向服务器建立连接
*
* @param seconds
* :为向服务器发起连接的超时时间<br>
*
* errorSnd:为发送期间可能出现异常的对象,一旦发生异常,完善异常对象信息然后抛出
*
* @return 没有返回值的内容
* @throws ErrorExcp
*
* @exception ErrorSend
* 抛出一个发送数据的异常
*/
public void conncet() throws ErrorExcp
{
try {
/**
* 从程序全局配置参数取出地址(地址,连接超时时间)
*/
ncpClient.connect(ParameterCfg.bankAdreess,
ParameterCfg.conncetTime);
} catch (IllegalArgumentException e) {
ErrorExcp error = new ErrorExcp(2, 1, 3, 301, "conncet");
throw error;
} catch (UnknownHostException e) {
ErrorExcp error = new ErrorExcp(2, 1, 3, 302, "conncet");
throw error;
} catch (IllegalBlockingModeException e) {
ErrorExcp error = new ErrorExcp(2, 1, 3, 303, "conncet");
throw error;
} catch (SocketTimeoutException e) {
ErrorExcp error = new ErrorExcp(2, 1, 3, 304, "conncet");
throw error;
} catch (IOException e) {
ErrorExcp error = new ErrorExcp(2, 1, 3, 305, "conncet");
throw error;
} finally {
close();
}
}
public void checkIsClose(int result, int errorCode, String info)
throws ErrorExcp {
if (ncpClient.isClosed()) {
ErrorExcp error = new ErrorExcp(1, result, 3, errorCode, info);
throw error;
}
}
/**
* 从套接字上发送一个字节数组
*
* @param sendByte
* : 为要发送的字节数组对象<br>
*
* start : 为尝试从sendByte的第start个字节开始发送<br>
*
* end : 表示发到到sendByte的第end个字节结束
*
* @return 没有返回值的内容
*
* @exception IllegalBlockingModeException
* 抛出一个使用了非阻塞套接字的异常<br>
* IOException 发送失败抛出一个IO异常(可能是网络突然中断)
*
*/
public void send(byte[] sendByte, int start, int end)
throws IllegalBlockingModeException, IOException {
writeIO = ncpClient.getOutputStream();
writeIO.write(sendByte, start, end);
writeIO.flush();
}
/**
* 在套接字上接受数据
*
* @param receviceMsg
* :表示要接受的报文字节数组
* @param start
* :表示从报文字节数组的哪一位直接序列开始接受
* @param end
* :表示从报文字节数组的哪一位结束数据的接受
* @return :返回接受了多少个字节的数据
* @throws ErrorExcp
* :如果接受时发现连接已经中断,抛出异常
* @throws IOException
* :如果接受数据异常,抛出IO异常
*/
private int receive(byte[] receviceMsg, int start, int end)
throws ErrorExcp, IOException
{
int length = -1;
receiveIO = ncpClient.getInputStream();
length = receiveIO.read(receviceMsg, start, end);
return length;
}
/**
* 发送报文数据的适配接口
*
* @param msg
* @throws ErrorExcp
*/
public void sendMsg(Msg msg) throws ErrorExcp
{
try {
send(msg.stdByte, 0, msg.stdByte.length);
} catch (IllegalBlockingModeException e) {
close();
ErrorExcp error = new ErrorExcp(2, 1, 3, 303, "SendMsg");
throw error;
}
catch (IOException e) {
close();
ErrorExcp error = new ErrorExcp(2, 1, 3, 305, "SendMsg");
throw error;
} catch (NullPointerException e) {
close();
ErrorExcp error = new ErrorExcp(2, 1, 3, 307, "SendMsg");
throw error;
}
}
/**
* 在套接字上收取一个报文
*
* @return
* @throws ErrorExcp
*/
public MsgInfo readMsg() throws ErrorExcp {
try {
/**
* 设置接受超时时间
*/
setRecTime();
/**
* 创建四个字节的数组,接受报文的msglength字段
*/
byte[] msgLength = new byte[4];
/**
* 接受头4个字节,并获取接受的直接的长度
*/
int recHeadLength = receive(msgLength, 0, 4);
/**
* 判断头4个字节的数据包是否接受完整
*/
if (recHeadLength != 4) {
ErrorExcp error = new ErrorExcp(1, 1, 1, 402, "msgLength");
throw error;
}
/**
* 将头4个字节写入日志
*/
log.addMsgHead(msgLength);
/**
* 写入报文长头四个字节信息
*/
msgInfo.msgLength = new String(msgLength);
/**
* 检查报文全局信息配置
*/
MsgGlobalInfo.macheingMsgLength(msgInfo);
int length = Integer.valueOf(msgInfo.msgLength);
/**
* 收取除报文头四个字节字段以外的全部报文
*/
byte rec[] = new byte[length];
/**
* 准备判断接受报文的长度是否达到期望的字节长度
*/
int recBodyLength;
recBodyLength = receive(rec, 0, length);
/**
* 判断数据包除头msgLength外,其他字段的长度是否正确
*/
if (recBodyLength != length) {
ErrorExcp error = new ErrorExcp(1, 1, 1, 404, "stdByte");
throw error;
}
String msgBody = new String(rec, 0, recBodyLength);
/**
* 将报文体写入日志
*/
log.addMsgBody(msgBody);
/**
* 完整的报文
*/
msgInfo.stdStr = msgInfo.msgLength + msgBody;
/**
* 写入报文编号信息
*/
msgInfo.msgNum = msgInfo.stdStr.substring(38, 41);
}
/**
* 捕捉连接中断的信息
*/
catch (IOException e) {
ErrorExcp error = new ErrorExcp(1, 1, 3, 407, "ReadMsg");
throw error;
}
return msgInfo;
}
/**
* 设置接受数据超时时间
*
* @throws ErrorExcp
*/
public void setRecTime() throws ErrorExcp {
try {
ncpClient.setSoTimeout(ParameterCfg.recTime);
} catch (SocketException e) {
ErrorExcp error = new ErrorExcp(2, 1, 3, 408, "setRecTime");
throw error;
}
}
public void close()
{
try {
/**
* 如果以前在catch 释放了则不需要在finally再次释放,否则可能会引发错误
*/
if (!isCloseDeal && !ncpClient.isClosed()) {
ncpClient.close();
}
} catch (Exception e) {
}
finally {
ncpClient = null;
isCloseDeal = true;
}
}
}
package Client;
import ErrorExcp.ErrorExcp;
import Msg.Msg.Msg;
/**
* 数据的接受与发送的抽象类
*
*/
public abstract class RecAndSnd
{
/**
* 缓存的日志对象
*/
public StringBuffer logInfo;
/**
* 通信对象
*/
public Client client;
/**
* 在套接字上发送一个报文
*
* @param msg
* 报文对象
* @throws ErrorExcp
*/
public abstract void send(Msg msg) throws ErrorExcp;
/**
* 在套接字上接受一个报文
*
* @return 报文对象Msg
* @throws ErrorExcp
*/
public abstract Msg read() throws ErrorExcp;
}
package Client;
import java.net.Socket;
import ErrorExcp.ErrorExcp;
import Log.Log;
import Msg.Msg.Msg;
import Msg.Msg.MsgFactory;
public class RecToSnd extends RecAndSnd
{
public RecToSnd(Log log, Socket accptSocket) {
client = new Client(accptSocket, log);
}
public void send(Msg msg) throws ErrorExcp {
try {
/**
* 检查发送前的连接是否正常
*/
client.checkIsClose(1, 306, "send");
client.sendMsg(msg);
}
/**
* 无论如何,对于银行发起的交易,应该断开连接
*/
finally {
client.close();
}
}
public Msg read() throws ErrorExcp
{
Msg msg = null;
MsgInfo msgInfo = null;
/**
* 接受套接字上的报文信息
*/
msgInfo = client.readMsg();
// /**
// * 如果非debug模式下,那么关闭连接(因为不需要应答)
// */
// if (!ParameterCfg.debug)
// {
// client.close();
// }
msg = MsgFactory.CreatMsg(msgInfo);
return msg;
}
}
package Client;
import ErrorExcp.ErrorExcp;
import Log.Log;
import Msg.Msg.Msg;
import Msg.Msg.MsgFactory;
import MsgCfg.MsgCfg;
/**
* 农产品发起交易时用到的通信类
*
*/
public class SndToRec extends RecAndSnd {
public MsgCfg msgCfg;
private SocketPool pool;
/**
* 从池中取出一个socket对象
*
* @param log
*/
public SndToRec(Log log) {
pool = SocketPool.getInstance();
client = new Client(pool.get(), log);
}
public void send(Msg msg) throws ErrorExcp {
/**
* 与银行服务器进行连接
*/
client.conncet();
/**
* 在套接字上发送一个报文
*/
client.sendMsg(msg);
}
/**
* 在套接字上接受发送后,银行返回的报文的信息
*
* @return 报文相关的信息
* @throws ErrorExcp
*/
public Msg read() throws ErrorExcp
{
Msg msg = null;
MsgInfo msgInfo = null;
try {
/**
* 检查连接是否正常
*/
client.checkIsClose(2, 406, "read");
msgInfo = client.readMsg();
} catch (ErrorExcp e) {
/**
* 因为是农产品发起的交易,没有收到数据,所以状态未明确
*/
e.result = 2;
throw e;
} finally {
client.close();
}
/**
* 如果出现接受的报文,不是发送报文所对应的报文应该报错,从此位置开始报文接受工作已经全部 完成
*/
if (msgCfg.relativeList.indexOf(msgInfo.msgNum) == -1) {
ErrorExcp error = new ErrorExcp(1, 1, 3, 501, "msgNum");
throw error;
}
/**
* 通过报文工厂创建报文
*/
msg = MsgFactory.CreatMsg(msgInfo);
return msg;
}
}
分享到:
相关推荐
本手册是根据中国银行网上银行银企对接前置机系统1.1编写的应用系统安装手册 。 由于编者水平有限,错误和疏漏在所难免,敬请读者谅解。随着银企对接系统的更新和发展,本手册的内容将不断修改和完善。 一、...
课程设计的银行系统,采用socket编程,java连接mysql数据库
基于jsp的银行ATM机系统设计,数据库用的是MySQL写的。需要写类似系统的朋友可以看一下哦。
一般性银行介入标准接口文档,帮助初接触银行接口开发人员实施。
前置机是实现银行传统业务向外拓展普遍采用的一种中间设备。它实现的主要功能有网络通信、报文认证、交易数据格式转换、个人密码PIN变换、交易流水记录、交易预处理、交易监控和交易数据统计等。目前在银行普遍采用...
内容包括:NSAE_NC用户手册_Linux.doc,NSAE_NC用户手册_Windows.doc,部署说明.docx,以及NC_3.1.3.2的Linux系统安装文件,NC_3.1.3.2的Windows系统安装文件
一个支持1376.1-2014规范的电能采集终端前置机软件程序,界面很友好。
376.1 前置机,支持TCP和UDP,需要安装.Net 4 Framework , 支持 1万+ 的终端和客户端连接数,web主站必备。
2 系统结构 整个前置机系统可以分为交易接口、交易处理核心、系统管理、监控系统四大部分 。结构框图如下: 3 处理模式和交易类型 1 处理模式 前置机与客户端之间,通过两次通讯完成一次交易 ,以减少通讯量 。首先...
克红的前置机。有兴趣的可以研究一下。复制联网的。
介绍了QT平台的特点,尤其它的跨平台特性,根据前置机的特点,给出了基于QT的前置机的软件开发 流程。基于QT的通信前置机真正实现了电力系统通信的跨平台操作。
招行银企直连前置机安装手册,适用于测试环境前置机及银企直连环境准备和安装!
前置机维护
用户数据在内网数据库里,外网不能直接查询,可以在前置机上部署一个接口应用,通过这个接口应用查询内网数据库,此接口应用支持
基础样例 测试舵机的前置样例 uart3通信部分
用户数据在内网数据库里,外网不能直接查询,可以在前置机上部署一个接口应用,通过这个接口应用查询内网数据库,此接口应用支持
农行银企直联Java开发相关代码 农行银企直联Java开发相关代码
邮件前置机功能相当于foxmail,可绑定多账号支持smtp、pop3、exchange等协议,并且可以通过灵活配置控制前置机工作
但当前SAP不支持SOCKET,所以就在前置机上做了一个TOMCAT服务,使用JAVA开发,把农银的SOCKET转换为HTTP提供出来,以方便SAP使用,然后SAP通过此代码实现读取或者操作农业银行的银企业直联前置机的功能。
银行前置平台基本原理