分布式架构从零开始========》【基于Java自身技术实现消息方式的系统间通信】
基于Java自身包实现消息方式的系统间通信的方式有:TCP/IP+BIO,TCP/IP+NIO,UDP/IP+BIO,UDP/IP+NIO.下面就这4种类型一一做个详细的介绍:
一.TCP/IP+BIO
在java中可基于Socket,ServerSocket来实现TCP/IP+BIO的系统间通信。Socket主要用于实现建立连接以及网络IO的操作,ServerSocket主要用于实现服务器端端口的监听及Socket对象的获取。基于Socket实现客户端的代码如下:
public class Client {
/**
* @param args
*/
public static void main(String[] args) throws Exception{
String host="127.0.0.1";
int port=9527;
Socket socket=new Socket(host,port);
BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out=new PrintWriter(socket.getOutputStream(),true);
BufferedReader systemIn=new BufferedReader(new InputStreamReader(System.in));
boolean flag=true;
while(flag){
String command=systemIn.readLine();
if(command==null || "quit".equalsIgnoreCase(command.trim())){
flag=false;
System.out.println("Client quit!");
out.println("quit");
out.close();
in.close();
socket.close();
continue;
}
out.println(command);
String response=in.readLine();
System.out.println(response);
}
}
}
服务器端代码如下:
public class Server {
/**
* @param args
*/
public static void main(String[] args) throws Exception{
int port=9527;
ServerSocket ss=new ServerSocket(port);
System.out.println("Server listen on port: "+port);
Socket socket=ss.accept();
BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out=new PrintWriter(socket.getOutputStream(),true);
while(true){
String line=in.readLine();
if(line==null){
Thread.sleep(100);
continue;
}
if("quit".equalsIgnoreCase(line.trim())){
in.close();
out.close();
ss.close();
System.out.println("Server has been shutdown!");
System.exit(0);
}
else{
System.out.println("Message from client: "+ line);
out.println("Server response:"+line);
Thread.sleep(100);
}
}
}
}
上面是基于Socket,ServerSocket实现的一个简单的系统间通信的例子。而在实际的系统中,通常要面对的是客户端同时要发送多个请求到服务器端,服务器端则同时要接受多个连接发送的请求,上面的代码显然是无法满足的。
为了满足客户端能同时发送多个请求到服务器端,最简单的方法就是生成多个Socket。但这里会产生两个问题:一是生成太多的Socket会消耗过多的本地资源,在客户端机器多,服务器端机器少的情况下,客户端生成太多Socket会
导致服务器端须要支撑非常高的连接数;二是生成Socket(建立连接)通常是比较慢的,因此频繁的创建会导致系统性能不足。鉴于这两个问题,通常采用连接池的方法来维护Socket是比较好的,一方面限制了能创建的Socket的个数;
另一个方面由于将Socket放入了池中,避免了重复创建Socket带来的性能下降的问题。数据库连接池就是这种方式的典型代表,但连接池的方式会带来另一个问题,连接池中的Socket的个数是有限的,但同时要用socket的请求可能会
很多,在这种情况下就会造成激烈的竞争和等待,还有一个需要注意的问题是合理控制等待响应的超时时间,如不设定会导致当服务器端处理变慢时,客户端相关的请求都在做无限的等待,二客户端的资源必然是有限的。因此这种情况
下很容易造成服务器端出问题时,客户端挂掉的现象。超时时间具体设置为多少取决于客户端能承受的请求量及服务器端的处理时间。既要保证性能,又要保证出错率不会过高,对于直接基于TCP/IP+BIO的方式,可采用Socket.setSotimeout来设置等待响应的超时时间。
二.TCP/IP+NIO
在java中可基于java.nio.channels中的Channel和Selector的相关类来实现TCP/IP+NIO方式的系统间通信。Channel有SocketChannel和ServerSocketChannnel两种,SocketChannel用于建立连接,监听事件及操作读写,
ServerSocketChannel用于监听端口及监听连接事件;程序通过Selector来获取是否有要处理的事件。基于这两个类实现客户端代码如下:
public class Client {
public static void main(String[] args) throws Exception{
int port=9527;
SocketChannel channel=SocketChannel.open();
channel.configureBlocking(false);
SocketAddress target=new InetSocketAddress("127.0.0.1",port);
channel.connect(target);
Selector selector=Selector.open();
channel.register(selector, SelectionKey.OP_CONNECT);
BufferedReader systemIn=new BufferedReader(new InputStreamReader(System.in));
while(true){
if(channel.isConnected()){
String command=systemIn.readLine();
channel.write(Charset.forName("UTF-8").encode(command));
if(command==null || "quit".equalsIgnoreCase(command.trim())){
systemIn.close();
channel.close();
selector.close();
System.out.println("Client quit!");
System.exit(0);
}
}
int nKeys=selector.select(1000);
if(nKeys>0){
for (SelectionKey key : selector.selectedKeys()) {
if(key.isConnectable()){
SocketChannel sc=(SocketChannel) key.channel();
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ);
sc.finishConnect();
}
else if(key.isReadable()){
ByteBuffer buffer=ByteBuffer.allocate(1024);
SocketChannel sc=(SocketChannel) key.channel();
int readBytes=0;
try{
int ret=0;
try{
while((ret=sc.read(buffer))>0){
readBytes+=ret;
}
}
finally{
buffer.flip();
}
if(readBytes>0){
System.out.println(Charset.forName("UTF-8").decode(buffer).toString());
buffer = null;
}
}
finally{
if(buffer!=null){
buffer.clear();
}
}
}
}
selector.selectedKeys().clear();
}
}
}
}
服务器端代码如下:
public class Server {
public static void main(String[] args) throws Exception{
int port=9527;
Selector selector=Selector.open();
ServerSocketChannel ssc=ServerSocketChannel.open();
ServerSocket serverSocket=ssc.socket();
serverSocket.bind(new InetSocketAddress(port));
System.out.println("Server listen on port: "+port);
ssc.configureBlocking(false);
ssc.register(selector, SelectionKey.OP_ACCEPT);
while(true){
int nKeys=selector.select(1000);
if(nKeys>0){
for (SelectionKey key : selector.selectedKeys()) {
if(key.isAcceptable()){
ServerSocketChannel server=(ServerSocketChannel) key.channel();
SocketChannel sc=server.accept();
if(sc==null){
continue;
}
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ);
}
else if(key.isReadable()){
ByteBuffer buffer=ByteBuffer.allocate(1024);
SocketChannel sc=(SocketChannel) key.channel();
int readBytes=0;
String message=null;
try{
int ret;
try{
while((ret=sc.read(buffer))>0){
readBytes+=ret;
}
}
catch(Exception e){
readBytes=0;
// IGNORE
}
finally{
buffer.flip();
}
if(readBytes>0){
message=Charset.forName("UTF-8").decode(buffer).toString();
buffer = null;
}
}
finally{
if(buffer!=null){
buffer.clear();
}
}
if(readBytes>0){
System.out.println("Message from client: "+ message);
if("quit".equalsIgnoreCase(message.trim())){
sc.close();
selector.close();
System.out.println("Server has been shutdown!");
System.exit(0);
}
String outMessage="Server response:"+message;
sc.write(Charset.forName("UTF-8").encode(outMessage));
}
}
}
selector.selectedKeys().clear();
}
}
}
}
三.UDP/IP+BIO
服务器端代码如下:
public class Server {
/**
* @param args
*/
public static void main(String[] args) throws Exception{
int port=9527;
int aport=9528;
DatagramSocket server=new DatagramSocket(port);
DatagramSocket client=new DatagramSocket();
InetAddress serverAddress=InetAddress.getByName("localhost");
byte[] buffer=new byte[65507];
DatagramPacket packet=new DatagramPacket(buffer,buffer.length);
while(true){
server.receive(packet);
String line=new String(packet.getData(),0,packet.getLength(),"UTF-8");
if("quit".equalsIgnoreCase(line.trim())){
server.close();
System.exit(0);
}
else{
System.out.println("Message from client: "+ line);
packet.setLength(buffer.length);
String response="Server response"+line;
byte[] datas=response.getBytes("UTF-8");
DatagramPacket responsePacket=new DatagramPacket(datas,datas.length,serverAddress,aport);
client.send(responsePacket);
Thread.sleep(100);
}
}
}
}
客户端代码如下:
public class Client {
/**
* @param args
*/
public static void main(String[] args) throws Exception{
int port=9527;
int aport=9528;
DatagramSocket serverSocket=new DatagramSocket(aport);
byte[] buffer=new byte[65507];
DatagramPacket receivePacket=new DatagramPacket(buffer,buffer.length);
DatagramSocket socket=new DatagramSocket();
InetAddress server=InetAddress.getByName("localhost");
BufferedReader systemIn=new BufferedReader(new InputStreamReader(System.in));
boolean flag=true;
while(flag){
String command=systemIn.readLine();
byte[] datas=command.getBytes("UTF-8");
DatagramPacket packet=new DatagramPacket(datas,datas.length,server,port);
socket.send(packet);
if(command==null || "quit".equalsIgnoreCase(command.trim())){
flag=false;
System.out.println("Client quit!");
socket.close();
continue;
}
serverSocket.receive(receivePacket);
String receiveResponse=new String(receivePacket.getData(),0,receivePacket.getLength(),"UTF-8");
System.out.println(receiveResponse);
}
}
}
四.UDP/IP+NIO
服务器端代码如下:
public class Server {
public static void main(String[] args) throws Exception{
int rport=9527;
int sport=9528;
DatagramChannel sendChannel=DatagramChannel.open();
sendChannel.configureBlocking(false);
SocketAddress target=new InetSocketAddress("127.0.0.1",sport);
sendChannel.connect(target);
DatagramChannel receiveChannel=DatagramChannel.open();
DatagramSocket serverSocket=receiveChannel.socket();
serverSocket.bind(new InetSocketAddress(rport));
System.out.println("Data receive listen on port: "+rport);
receiveChannel.configureBlocking(false);
Selector selector=Selector.open();
receiveChannel.register(selector, SelectionKey.OP_READ);
while(true){
int nKeys=selector.select(1000);
if(nKeys>0){
for (SelectionKey key : selector.selectedKeys()) {
if(key.isReadable()){
ByteBuffer buffer=ByteBuffer.allocate(1024);
DatagramChannel dc=(DatagramChannel) key.channel();
dc.receive(buffer);
buffer.flip();
String message=Charset.forName("UTF-8").decode(buffer).toString();
System.out.println("Message from client: "+ message);
if("quit".equalsIgnoreCase(message.trim())){
dc.close();
selector.close();
sendChannel.close();
System.out.println("Server has been shutdown!");
System.exit(0);
}
String outMessage="Server response��"+message;
sendChannel.write(Charset.forName("UTF-8").encode(outMessage));
}
}
selector.selectedKeys().clear();
}
}
}
}
客户端代码如下:
public class Client {
public static void main(String[] args) throws Exception{
int rport=9528;
int sport=9527;
DatagramChannel receiveChannel=DatagramChannel.open();
receiveChannel.configureBlocking(false);
DatagramSocket socket=receiveChannel.socket();
socket.bind(new InetSocketAddress(rport));
Selector selector=Selector.open();
receiveChannel.register(selector, SelectionKey.OP_READ);
DatagramChannel sendChannel=DatagramChannel.open();
sendChannel.configureBlocking(false);
SocketAddress target=new InetSocketAddress("127.0.0.1",sport);
sendChannel.connect(target);
BufferedReader systemIn=new BufferedReader(new InputStreamReader(System.in));
while(true){
String command=systemIn.readLine();
sendChannel.write(Charset.forName("UTF-8").encode(command));
if(command==null || "quit".equalsIgnoreCase(command.trim())){
systemIn.close();
sendChannel.close();
selector.close();
System.out.println("Client quit!");
System.exit(0);
}
int nKeys=selector.select(1000);
if(nKeys>0){
for (SelectionKey key : selector.selectedKeys()) {
if(key.isReadable()){
ByteBuffer buffer=ByteBuffer.allocate(1024);
DatagramChannel dc=(DatagramChannel) key.channel();
dc.receive(buffer);
buffer.flip();
System.out.println(Charset.forName("UTF-8").decode(buffer).toString());
buffer = null;
}
}
selector.selectedKeys().clear();
}
}
}
}
分布式架构从零开始========》【基于Java自身技术实现消息方式的系统间通信】的更多相关文章
- 基于java自身技术实现消息方式的系统间通信
这篇博客基本照搬了分布式java应用基础与实践一书的内容 java自带的远程调用分两种一种是rmi,一种是webservice 我们先看rmi(remote method invoke)# 使用rmi ...
- 基于JAVA WEB技术旅游服务网站系统设计与实现网上程序代写
基于JAVA WEB技术旅游服务网站系统设计与实现网上程序代写 专业程序代写服务(QQ:928900200) 随着社会的进步.服务行业的服务水平不断发展与提高,宾馆.酒店.旅游等服务行业的信息量和工作 ...
- 基于java开发的在线题库系统tamguo
简介 探果网(简称tamguo)是基于java开发的在线题库系统,包括 在线访问 后台运营 会员中心 书籍中心 管理员账号:system 密码:123456 因为线上数据和测试数据没有做到隔离,作者已 ...
- 系统间通信——RPC架构设计
架构设计:系统间通信(10)——RPC的基本概念 1.概述经过了详细的信息格式.网络IO模型的讲解,并且通过JAVA RMI的讲解进行了预热.从这篇文章开始我们将进入这个系列博文的另一个重点知识体系的 ...
- 系统间通信(5)——IO通信模型和JAVA实践 下篇
7.异步IO 上面两篇文章中,我们分别讲解了阻塞式同步IO.非阻塞式同步IO.多路复用IO 这三种IO模型,以及JAVA对于这三种IO模型的支持.重点说明了IO模型是由操作系统提供支持,且这三种IO模 ...
- 架构设计:系统间通信(20)——MQ:消息协议(下)
(接上文<架构设计:系统间通信(19)--MQ:消息协议(上)>) 上篇文章中我们重点讨论了"协议"的重要性.并为各位读者介绍了Stomp协议和XMPP协议. 这两种协 ...
- 架构设计:系统间通信(34)——被神化的ESB(上)
1.概述 从本篇文章开始,我们将花一到两篇的篇幅介绍ESB(企业服务总线)技术的基本概念,为读者们理清多个和ESB技术有关名词.我们还将在其中为读者阐述什么情况下应该使用ESB技术.接下来,为了加深读 ...
- 系统间通信(3)——IO通信模型和JAVA实践 上篇
来源:http://blog.csdn.net/yinwenjie 1.全文提要 系统间通信本来是一个很大的概念,我们首先重通信模型开始讲解.在理解了四种通信模型的工作特点和区别后,对于我们后文介绍搭 ...
- Java多线程学习(五)线程间通信知识点补充
系列文章传送门: Java多线程学习(二)synchronized关键字(1) Java多线程学习(二)synchronized关键字(2) Java多线程学习(三)volatile关键字 Java多 ...
随机推荐
- PHP邮件注入攻击技术
1. 简介 如 今,互联网的使用急剧上升,但绝大多数互联网用户没有安全知识背景.大多数的人都会使用互联网通过邮件Email的方式和他人进行通信.出于这个原因,大 多数网站允许他们的用户联系他们,向网站 ...
- LeetCode 65 Valid Number
(在队友怂恿下写了LeetCode上的一个水题) 传送门 Validate if a given string is numeric. Some examples: "0" =&g ...
- DLUTOJ 1209 字典序和r-子集
传送门 Time Limit: 6 Sec Memory Limit: 128 MBSubmit: 73 Solved: 14 Description Input 多组输入数据. 每组数据: 第一 ...
- C#面向对象中类的静态成员与非静态成员的区别
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- centOS下yum安装配置samba
centOS下yum安装配置samba 2010-03-29 15:46:00 标签:samba yum centOS 安装 休闲 注意:本文的原则是只将文件共享应用于内网服务器,并让将要被共享的目 ...
- Hibernate检索策略(抓取策略)(Hibernate检索优化)
一.查询方法中get方法采用策略是立即检索,而load方法采用策略是延迟检索,延迟检索是在使用数据时才发送SQL语句加载数据 获取延迟加载数据方式:1.使用的时候,如果Customer c=sessi ...
- Spring MVC实现文件上传
基础准备: Spring MVC为文件上传提供了直接支持,这种支持来自于MultipartResolver.Spring使用Jakarta Commons FileUpload技术实现了一个Multi ...
- js正则表达式中的问号几种用法小结
这篇文章主要介绍了js正则表达式中的问号几种用法,比如+?,*?,{2,3}?可以停止匹配的贪婪模式,感兴趣的朋友可以参考下 在表示重复的字符后面加问号,比如+?,*?,{2,3}?可以停止匹配的贪婪 ...
- Python打包程序
到py2exe的官网下载程序,注意对应的python版本,比如所用的python版本为2.7,那么就下载适配2.7版本的py2exe软件 下载完成后安装(与普通软件安装方式相同) 2 将要转换的pyt ...
- Struts.xml讲解
解决在断网环境下,配置文件无提示的问题我们可以看到Struts.xml在断网的情况下,前面有一个叹号,这时,我们按alt+/ 没有提示,这是因为” http://struts.apache.org/d ...