基于TCP协议的项目架构之Socket流传输的实现
项目背景
某银行的影像平台由于使用时间长,服务器等配置原因,老影像系统满足不了现在日益增长的数据量的需求,所以急需要升级改造。传统的影像平台使用的是Oracle数据库和简单的架构来存储数据(视频、图片等),所以很难满足现在的业务需求,其中最主要的就是存储下载等速度的影响,综合考虑之后,我们给出了升级改造方案,基于Http协议的数据传输和基于TCP协议的数据传输,按照要求需要用TCP协议,我们最终采用的是Socket网络传输的方案。
TCP协议介绍
TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议,在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能,TCP层位于IP层之上,应用层之下的中间层,不同主机的应用层之间经常需要可靠的、像管道一样的连接,但IP层不需要提供这样的机制,而是提供不可靠的包交换。当应用层向TCP层发送用于网间传输的、用8位字节标示的数据流,TCP会把数据流分割为适当长度的报文段,之后TCP把数据包传给IP层,由它来通过网络将包传输给接收端的实体TCP层。TCP是因特网中的传输层协议,使用3次握手协议建立连接。
Socket
TCP通信是严格区分客户端与服务端的,在通信时,必须先由客户端去连接服务器才能实现通信,服务器端不可以主动连接客户端,并且服务器要事先启动,等待客户端的连接。
在JDK中提供了两个类用于实现TCP程序,一个是ServerSocket类,用于表示服务器,一个是Socket类,用于表示客户端。通信时,首先创建代表服务器端的ServerSocket对象,该对象相当于开启一个服务,并等待客户端的连接,然后创建代表客户端的Socket对象向服务器端发出连接请求,服务器端响应请求,两者建立连接,开始通信。
下面是我们通过Socket建立的模型,是多线程的,首先看服务端代码:
/**
* socket服务端
* @author 我心自在
*
*/
public class Main {
private static Log logger=null;
//线程池
public static ExecutorService executor =null;
/**
* 静态块,初始化
*/
static{
logger=LogFactory.getLog(SocketMain.class);
//线程池
executor = Executors.newFixedThreadPool(123);
}
/**
* 主程序入口
* @param args
*/
public static void main(String[] args) {
ServerSocket server = null;
Socket socket = null;
PropertiesUtil PropertiesUtil = new PropertiesUtil();
try {
//启动Socket服务端
server=newServerSocket(23232);
while (true) {
//多线程接收客户端请求
socket = server.accept();
if (socket != null) {
executor.execute(new Controller(socket));
}
}
} catch (IOException e) {
logger.error("Main IO异常:"+e.getMessage(),e);
} finally {
try {
if (server != null) {
server.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
logger.error("Main流关闭异常:"+e.getMessage(),e);
}
}
}
}
下面是业务处理类,支持多线程,主要用来处理业务
public class Controller implements Runnable {
private Socket socket;
private static Log logger=LogFactory.getLog(SocketController.class);
public SocketController(Socket socket) {
super();
this.socket = socket;
}
public void run() {
//读取文件流
String requestMethod=null;
Map<String,Object> getMethAndNumMap=null;
Map<String,Object> jsonMap=null;
BufferedInputStream bis =null;
OutputStream ops = null;
BufferedWriter bw = null;
BufferedOutputStream bos = null;
Document doc=null;
String XMLString=null;
try {
bis= new BufferedInputStream (socket.getInputStream());
//获取输出流
ops = socket.getOutputStream();
bos = new BufferedOutputStream(ops);
bw = new BufferedWriter(new OutputStreamWriter(ops));
byte[] fileinfo=new byte[256];
try {
bis.read(fileinfo);
} catch (IOException e1){
logger.error("流读取异常...."+e1.getMessage(),e1);
}
if(fileinfo!=null){
fileInfoString=new String(fileinfo).trim();
}
jsonMap=JSONUtil.jsonToMap(fileInfoString);
requestMethod=(String) jsonMap.get("requestMethod");
if (!(requestMethod==null||"".equals(requestMethod))) {
switch (requestMethod){
case "login":
Login.login(XMLString,bw,doc);//登录接口
break;
case "XXXX":
XXX.xxx();
break;
default:
//请求方法错误 }
}
} catch (UnknownHostException e) {
logger.error("Socket未知端口:"+e.getMessage(),e);
} catch (IOException e) {
logger.error("Controller读流流异常:"+e.getMessage(),e);
}finally{
try {
if (bw!=null) {
bw.flush();
bw.close();
}
if(ops!=null){
ops.close();
}
if(bos!=null){
bos.close();
}
bis.close();
socket.close();
} catch (IOException e) {
logger.error("socket关闭异常:"+e.getMessage(),e);
}
}
}
这是一个完整的Socket传输框架,基本思想就是,通过输入流接到客户端发送过来的报文,然后进行解析,为什么统一用字节流接受呢,这里由具体的业务流程决定,因为我们的文件上传分两部分,一部分是文件信息,一部分是文件流,所以为了方便,统一使用字节流接收,根据字节流中的请求接口方法,调用对应的接口方法,完成业务处理。因为客户端的报文有两种,一种是XML类型的报文,另外一种是json格式的报文,这里只贴出了部分json格式的代码。差的只是一个XML的解析,解析方式很多,就不再赘述。
下面是客户端代码,以登录为例:
public class LoginTest {
public static void main(String[] args) {
String xml =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<root>"
+ "<requestMethod>login</requestMethod>"
+ "<userinfo>"
+ "<loginname>test</loginname>"
+ "<passwd>123456</passwd>"
+ "</userinfo>"
+ "</root>";
Socket socket=null;
BufferedWriter bw=null;
BufferedReader br=null;
try {
socket=new Socket(”10.182.1.100“, 23232);
bw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write(xml);
bw.newLine();
bw.flush();
br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println("服务器返回报文:"+br.readLine());
bw.close();
br.close();
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
客户端代码非常简单,基本就是以流的形式发送报文,发送到客户端,完成请求,收到服务器响应后,关闭连接,完成一次请求。
以上只是一个简单的Socket通信模型,可以应用到很多不同的项目。大致思路就是通过Socket通信,获取客户端发送过来的报文,然后对报文进行解析,根据请求方法,调用不同的业务接口,处理不同的业务,结合不同的场景,执行不同的操作。
基于TCP协议的项目架构之Socket流传输的实现的更多相关文章
- 网络编程(二)--TCP协议、基于tcp协议的套接字socket
一.TCP协议(Transmission Control Protocol 传输控制协议) 1.可靠传输,TCP数据包没有长度限制,理论上可以无限长,但是为了保证网络的效率,通常TCP数据包的长度不会 ...
- 网络编程(二)——TCP协议、基于tcp协议的套接字socket
TCP协议与基于tcp协议的套接字socket 一.TCP协议(流式协议) 1.可靠传输,TCP数据包没有长度限制,理论上可以无限长,但是为了保证网络的效率,通常TCP数据包的长度不会超过IP数据包的 ...
- JAVA 基于TCP协议的一对一,一对多文件传输实现
最近老师给我们上了多线程和TCP和UDP协议,其中一个要求就是我们用JAVA协议一个基于TCP和UDP这两种协议的一对一文件上传和一对多文件上传. 然后我就开始分析TCP和UDP这两个协议的特点,发现 ...
- 基于Tcp协议的简单Socket通信实例(JAVA)
好久没写博客了,前段时间忙于做项目,耽误了些时间,今天开始继续写起~ 今天来讲下关于Socket通信的简单应用,关于什么是Socket以及一些网络编程的基础,这里就不提了,只记录最简单易懂实用的东西. ...
- (2)socket的基础使用(基于TCP协议)
socket()模块函数用法 基于TCP协议的套接字程序 netstart -an | findstr 8080 #查看所有TCP和UDP协议的状态,用findstr进行过滤监听8080端口 服务端套 ...
- 网络编程----socket介绍、基于tcp协议的套接字实现、基于udp协议的套接字实现
一.客户端/服务器架构(C/S架构) 即C/S架构,包括: 1.硬件C/S架构(打印机) 2.软件C/S架 ...
- [网络编程之Socket套接字介绍,套接字工作流程,基于TCP协议的套接字程序]
[网络编程之Socket套接字介绍,套接字工作流程,基于TCP协议的套接字程序] 为何学习socket套接字一定要先学习互联网协议: 1.首先:要想开发一款自己的C/S架构软件,就必须掌握socket ...
- 网络编程——基于TCP协议的Socket编程,基于UDP协议的Socket编程
Socket编程 目前较为流行的网络编程模型是客户机/服务器通信模式 客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求.如图所示,通常,一个服务器进程会同时为多个客户端进程服务,图中服 ...
- 基于TCP协议的socket套接字编程
目录 一.什么是Scoket 二.套接字发展史及分类 2.1 基于文件类型的套接字家族 2.2 基于网络类型的套接字家族 三.套接字工作流程 3.1 服务端套接字函数 3.2 客户端套接字函数 3.3 ...
随机推荐
- 機器學習基石(Machine Learning Foundations) 机器学习基石 课后习题链接汇总
大家好,我是Mac Jiang,非常高兴您能在百忙之中阅读我的博客!这个专题我主要讲的是Coursera-台湾大学-機器學習基石(Machine Learning Foundations)的课后习题解 ...
- 设计模式 - 装饰者模式(Decorator Pattern) 具体解释
装饰者模式(Decorator Pattern) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26707033 装饰者 ...
- dynamic programming 学习
这是看到一位大神,写的关于dynamic programming的博客,认为很好.简单分析下.然后给出链接. 背景问题就是 有一个国家,全部的国民都很老实憨厚,某天他们在自己的国家发现了十座金矿.而且 ...
- android checkbox 未选中状态 已选中状态 替换成自己的图片
效果图: 未选中状态: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA ...
- 近期对FTP及Excel数据处理的一些摸索
一个多月没写随笔了,主要是发的东西,自己感觉也很垃圾,说又说回来,谁不是从垃圾变强的,所以不比比,还得努力.come on!! Python学习也有段时间了,近期为了解决同事的一个难题,所以我们决定联 ...
- Objective-C 和 Swift 混编项目的小 Tips(一)
本文主要闲聊一些 Objective-C 和 Swift 混编项目带来的一些潜规则,希望能帮到对此感到疑惑的朋友.下面我们开始进入主题: 命名 官方 Guide 上只是简单叙述(Using Swift ...
- 二、springcloud Netflix 注册中心
Eureka是Netflix开源的一款提供服务注册和发现的产品,它提供了完整的Service Registry和Service Discovery实现.也是springcloud体系中最重要最核心的组 ...
- flask中的session,render_template()第二和参数是字典
1. 设置一个secret_key 2.验证登入后加上session,这是最简单,不保险 . 3.注意render_template传的参数是字典
- Pseudo-devices On GNU/Linux
先分享一则有意思Q&A,来自The FreeBSD Funnies 17.4 . Where does data written to* /dev/null* go? It goes in ...
- 微信小程序教学第三章(含视频):小程序中级实战教程:列表-页面逻辑处理
§ 页面逻辑处理 本文配套视频地址: https://v.qq.com/x/page/n0554dndrez.html 开始前请把 ch3-2 分支中的 code/ 目录导入微信开发工具 修改 ind ...