笔者进来遇到一个项目,一家公司的系统需要在完成自身业务逻辑的同时,接入到某银行的核心系统(这里准确说应该是前置机)进行一系列的账务处理,然后再将账务处理结果返回给该公司系统。

网络通信采用TCP协议。

由于公司方和银行的TCP协议报文有所不同,故整个项目的方案是在两者之间架设一个转发机(由银行方提供),用来进行协议报文的转换。

分析一下,整个系统的交易分为一下几个部分:

1、需要在转发机上建立一个socket服务器程序,用来监听来自于公司方的socket请求。

2、收到该请求后,分配一个线程,执行该请求逻辑,包括:

(1)、接收公司方的协议报文,转换为银行前置机报文

(2)、将转换后的报文发送给银行前置机

(3)、银行前置机接收转发机报文并执行账务处理,而后将结果发送给转发机

(4)、转发机读取前置机返回的报文,转换为公司方协议报文,并发送给公司方

(5)、公司方收到转发机返回的结果

以上为了简化,我们采用阻塞式IO设计,即在一个过程中按顺序执行上述(1)到(5)的步骤。

另外,同样为了简化我们的程序设计,并不在转发机的socket服务器程序上采用线程池设计。

package com.zjjs.server;

import java.io.IOException;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket; import org.apache.log4j.Logger;
/**
* create by linyang 2015-09-18
* 套接字服务器
* 监听来自第三方的请求,对于每个请求启动一个处理线程
* **/
public class ZjjsTransServer {
private static final int _PORT_ = 9091;
private static Logger logger = Logger.getLogger(ZjjsTransServer.class); public static void main(String args[]) {
try {
ServerSocket server = new ServerSocket(_PORT_);
logger.info("socket服务器启动,端口[" + _PORT_ + "]...");
while (true) {
Socket nextClient = server.accept();
logger.info("接收到来自:" + nextClient.getInetAddress() + "["
+ nextClient.getPort() + "]的请求/n" + "socket hashcode["
+ nextClient.hashCode() + "]");
SocketHandler handler = new SocketHandler(nextClient);
Thread t = new Thread(handler);
t.start();
}
} catch (BindException be) {
logger.error("socket服务器端口冲突" + _PORT_);
} catch (IOException ioe) {
logger.error("I/O error" + ioe);
}
}
}
package com.zjjs.server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket; import org.apache.log4j.Logger; import com.zjjs.trans.Trans;
import com.zjjs.trans.ZjjsTrans;
/**
* create by linyang 2015-09-18
* 套接字请求处理线程
* 完成 接收第三方--->发送前置机--->接收前置机--->发送第三方 等步奏
* **/
public class SocketHandler implements Runnable { private Socket socket = null;
private Socket frontSocket = null;
private static Logger logger = Logger.getLogger(SocketHandler.class); public SocketHandler(Socket socket) {
super();
this.socket = socket;
} @Override
public void run() {
String datagram = null;
String send2frontDatagram = null;
ZjjsTrans transProcesser = null;
String transCode = "";
Trans trans = null;
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(
this.socket.getInputStream()));
datagram = reader.readLine();
logger.info("接收到第三方报文" + datagram);
transCode = datagram.substring(4, 8);
try {
try {
trans = (Trans) Class.forName("com.zjjs.trans.Trans" + transCode)
.newInstance();
} catch (InstantiationException inse) {
inse.printStackTrace();
logger.error("实例化交易失败,交易类型" + "Trans" + transCode + ", "
+ inse);
} catch (IllegalAccessException ille) {
ille.printStackTrace();
logger.error("实例化交易失败IllegalAccessException,交易类型" + "Trans"
+ transCode + ", " + ille);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
logger.error("未找到交易类型" + "com.zjjs.trans.Trans" + transCode + ", " + e);
} transProcesser = new ZjjsTrans(trans);
logger.info("解析收到第三方报文开始...");
transProcesser.parserDatagramReceive(datagram);
logger.info("解析收到第三方报文结束");
logger.info("开始生成转发到前置机报文...");
send2frontDatagram = transProcesser.toFrontServerDatagram();
logger.info("结束生成转发到前置机报文,报文内容[" + send2frontDatagram + "]"); frontSocket = new Socket("158.222.65.155", 8008);
logger.info("开始向前置机发送报文...");
PrintWriter printer = new PrintWriter (new OutputStreamWriter(frontSocket.getOutputStream()));
/*
OutputStreamWriter writer = new OutputStreamWriter(
frontSocket.getOutputStream()); */
printer.println(send2frontDatagram);
printer.flush();
//printer.close();
logger.info("向前置机发送报文结束"); logger.info("开始接收前置机返回报文...");
BufferedReader frontreader = new BufferedReader(new InputStreamReader(frontSocket.getInputStream()));
String frontReturnDatagram = frontreader.readLine();
printer.close();
logger.info("前置机返回报文[" + frontReturnDatagram + "]");
logger.info("接收前置机返回报文结束"); logger.info("开始将前置机返回报文转换为返回给第三方报文...");
String toThirdDatagram = transProcesser.toThirdServerDatagram(frontReturnDatagram);
logger.info("转换后返回第三方报文[" + toThirdDatagram + "]");
logger.info("将前置机返回报文转换为返回给第三方报文结束"); logger.info("开始向第三方返回结果报文...");
/*
Socket toThirdSocket = new Socket("xxxxx", 8008);
PrintWriter thirdPrinter = new PrintWriter (new OutputStreamWriter(toThirdSocket.getOutputStream()));
thirdPrinter.println(toThirdDatagram);
thirdPrinter.flush();
thirdPrinter.close();
*/
logger.info("向第三方返回结果报文结束"); } catch (IOException ioe) {
logger.error("I/O error:" + ioe);
}
} }

2015-11-6 补充,上述程序存在一定隐患,http://www.cnblogs.com/lyhero11/p/4943433.html

如何使用socket进行java网络编程(一)的更多相关文章

  1. 如何使用socket进行java网络编程(二)

    通过在如何使用socket进行java网络编程(一)中程序的编写,可以总结出一些常用的java socket编程的范例来. ServerSocket server = new ServerSocket ...

  2. 如何使用socket进行java网络编程(三)

    本篇文章继续记录java网络通讯编程的学习.在本系列笔记的第一篇中曾经记录过一个项目中的程序,当时还处于项目早期,还未进入与第三方公司的联调阶段,笔者只是用java写了一个client程序模拟了一下第 ...

  3. 如何使用socket进行java网络编程(四)

    在上一篇的结尾,提到过用来处理每一个服务端accept到的socket,我们由原来最开始的单线程改成了多线程去处理,但是对每一个接收到的socket都new一个thread去处理,这样效率太低,我们需 ...

  4. 如何使用socket进行java网络编程(五)

    本篇记录: 1.再谈readLine()方法 2.什么是真正的长连接 最近又参与了一个socket的项目,又遇到了老生常谈的readLine()问题:对方通过其vb程序向我方socketServer程 ...

  5. java 网络编程复习(转)

    好久没有看过Java网络编程了,现在刚好公司有机会接触,顺便的拾起以前的东西 参照原博客:http://www.cnblogs.com/linzheng/archive/2011/01/23/1942 ...

  6. Java 网络编程(转)

    一,网络编程中两个主要的问题 一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输. 在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可 ...

  7. 关于Java网络编程

    一,网络编程中两个主要的问题 一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输. 在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可 ...

  8. java网络编程socket解析

    转载:http://www.blogjava.net/landon/archive/2013/07/02/401137.html Java网络编程精解笔记2:Socket详解 Socket用法详解 在 ...

  9. Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制

    Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制 JAVA 中原生的 socket 通信机制 摘要:本文属于原创,欢迎转载,转载请保留出处:https://github.co ...

随机推荐

  1. OC - GCD 队列组 - 下载图片画图

    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ [self downloadIma ...

  2. 43-python-自己的词典

    可以用python实现一个自己的词典, 就是在网上下一个英汉词典,作为自己的词库,然后整理出一个json文件,存起来,查词时,直接读取查询: 处理时可以用正则表达式处理: https://www.cn ...

  3. LayDate 时间选择插件的使用介绍 (低版本1.0好像是)

    <span style="font-size:18px;"><!doctype html> <html> <head> <me ...

  4. Codeforces 681C. Heap Operations 优先队列

    C. Heap Operations time limit per test:1 second memory limit per test:256 megabytes input:standard i ...

  5. Codeforces 689B. Mike and Shortcuts SPFA/搜索

    B. Mike and Shortcuts time limit per test: 3 seconds memory limit per test: 256 megabytes input: sta ...

  6. 在EF中使用MySQL的方法及常见问题

    有时需要在网上租用空间或数据库,Mysql成本低一些,所以想将sql server转成mysql…… 注意:在安装Mysql时要选择文字集为utf8,否则将不能使用中文(当前也可以在创建数据库时使用u ...

  7. 20155317 王新玮 2016-2017-2 《Java程序设计》第9周学习总结

    20155317 王新玮 2016-2017-2 <Java程序设计>第9周学习总结 教材学习内容总结 数据库本身是个独立运行的应用程序 撰写应用程序是利用通信协议对数据库进行指令交换,以 ...

  8. 2018.06.29 洛谷P1505 [国家集训队]旅游(树链剖分)

    旅游 题目描述 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T 城的任意两个景点之间有且只有 ...

  9. 2018.09.20 atcoder 1D Reversi(模拟)

    传送门 考虑每次摆石头都会消去最外层的一个连续颜色串. 所以只用统计一下有多少段颜色即可. 代码: #include<bits/stdc++.h> using namespace std; ...

  10. 2018.07.18 [NOI2018]归程(return)(kruskal重构树)

    传送门 新鲜出炉的noi2018试题. 下面讲讲这题的解法: 首先要学习一个叫做kruskal重构树的东东. 听名字就知道跟kruskal算法有关,没错,原来的kruskal算法就是用并查集实现的,但 ...