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;
}
}
分享到:
相关推荐
在本项目中,"java 银行系统 socket 数据库"是一个基于Java语言开发的银行管理系统,它利用了Socket编程来实现客户端与服务器之间的通信,并且通过MySQL数据库存储和管理银行的各种数据。以下是对这个系统的关键知识...
【银行前置机ATM机系统设计】是一种在银行业务中广泛应用的技术,主要目的是为了提供便捷的自助服务,如存取款、查询余额等。在这个基于JSP(JavaServer Pages)的系统设计中,ATM机的功能被模拟并实现,用户可以...
本手册是根据中国银行网上银行银企对接前置机系统1.1编写的应用系统安装手册 。 由于编者水平有限,错误和疏漏在所难免,敬请读者谅解。随着银企对接系统的更新和发展,本手册的内容将不断修改和完善。 一、...
前置机程序在IT行业中扮演着重要的角色,尤其在分布式系统和网络通信中。"376.1 前置机程序"是一个专为大型网络环境设计的软件组件,它支持TCP(传输控制协议)和UDP(用户数据报协议)这两种主要的网络通信协议。...
前置机是实现银行传统业务向外拓展普遍采用的一种中间设备。它实现的主要功能有网络通信、报文认证、交易数据格式转换、个人密码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采集终端前置机程序》是一款符合中国国家标准GB/T 1376.1-2014的电力数据采集系统的重要组成部分,其主要功能是作为采集终端与后台系统之间的桥梁,实现数据的高效、准确传输。这款软件具备用户...
这种情况下,我们需要采用一种安全的方式来实现外网用户对内网数据库的数据访问,这就是"前置机接口"的概念。前置机接口是一种中间层应用,它部署在内外网之间的安全边界上,负责接收外网请求,然后转发到内网数据库...
新南网终端前置机是电力行业中用于数据采集与监控系统(SCADA)的重要组成部分,它在新南方电网的自动化系统中扮演着关键角色。标题中的“新南网终端前置机南网13”指的是该软件版本是专为新南方电网设计的第13版...
在IT领域,邮件系统是企业通信的核心组成部分,而“邮件前置机”则是一个重要的概念,它扮演着管理和处理电子邮件的关键角色。标题中的“邮件前置机相当于后台foxmail”揭示了邮件前置机的功能与个人邮箱客户端...
系统的主要功能在于接收和处理来自各种终端设备(如POS机、银行网点、医疗机构等)的交易请求,通过预处理、存储和转发,确保电子支付交易的顺利完成。 在系统概述中,前置机扮演着承上启下的角色,作为二级服务器...
4. 通信前置机角色:通信前置机在SCADA系统中扮演着至关重要的角色。它是实时数据输入、输出的主要门户,负责处理调度控制中心与下属厂站之间、与上下级调度控制中心之间以及调度中心内部后台系统之间的实时数据通信...
“客户端代理”则意味着这个代理服务是通过一个客户端程序来实现的,这个客户端可能是一个应用程序或者脚本,负责接收和处理外网的请求,以及与前置机的交互。 根据压缩包子文件的文件名称“proxy”,我们可以推测...
由于银行后台核心系统普遍采用的是UNIX下C/C++的开发平台,如果需要调Web Service往往需要借助一些第三方的库,再加上第三方的加解密算法及包是由第三方提供的,如果直接在UNIX下开发项目成本会比较高,所以增加了一...
克红的前置机。有兴趣的可以研究一下。复制联网的。
招行银企直连对接Java示例是一种在企业与银行之间建立直接电子连接的技术,用于自动化处理财务交易,如支付、转账、查询余额等。这个Java demo是招商银行提供的一个开发模板,帮助开发者理解并实现银企直连的流程。 ...
首先,前置机是专门用于与ESB系统通信的设备,不应用于生产或准生产环境。因此,它的角色是作为数据的中介,将数据桥接到部门内部的生产库或接收生产库的数据。 在硬件方面,前置机推荐配置如下: 1. CPU:至少2-4...