程序思路逻辑:
A.服务器代码:(可多线程同时上线多台服务器)
主函数
1.连接zookeeper
2.注册服务器
3.开始提供业务(无论请求是什么,都返回当前时间)
B.服务逻辑代码-实现-无论请求是什么,都返回当前时间
C.客户端
主函数
1.new一个自己的对象(客户端)
2.构造zk连接对象
3.查询在线服务器列表
4.处理业务(向一台服务器发送时间查询请求)
- 服务器代码
package cn.edu360.zk.gwtest;
import java.io.IOException;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import cn.edu360.zk.distributesystem.TimeQueryService;
public class TimerQuServer {
ZooKeeper zk = null;
//连接zookeeper的方法
public void getConnectZK() throws Exception{
zk = new ZooKeeper("hdp01:2181,hdp02:2182,hdp03:2181", 2000, null);
}
//注册服务器的方法
public void createServer(String hostname,String port) throws Exception{
//判断当前服务器总目录,是否存在,如果不存在则创建
Stat exists = zk.exists("/Servers", false);
if(exists==null){
zk.create("/Servers", "服务器总目录".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
//注册子服务器
String server = zk.create("/Servers/Server", (hostname+":"+port).getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
System.out.println("注册服务器成功,服务器地址:"+server);
}
//主函数
// 1.连接zookeeper
// 2.注册服务器
// 3.开始提供业务
public static void main(String[] args) {
TimerQuServer timerQuServer = new TimerQuServer();
try {
timerQuServer.getConnectZK();
timerQuServer.createServer(args[0], args[1]);
// 启动业务线程开始处理业务
new TimeQueryService(Integer.parseInt(args[1])).start();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
- 服务逻辑代码
package cn.edu360.zk.gwtest;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
public class TimerQuService extends Thread {
//1 需要一个端口号 构造函数直接传
int port = 0;
public TimerQuService(int port) {
this.port = port;
}
//重新run方法
@Override
public void run() {
// TODO Auto-generated method stub
try {
//创建一个服务器对象
ServerSocket socket = new ServerSocket(port);
System.out.println("业务线程已绑定端口:"+port+"准备接受客户端请求");
while(true){
//等待接收客户端请求
Socket accept = socket.accept();
//获取客户端的情况
InputStream in = accept.getInputStream();
//发出给客户端的响应
OutputStream out = accept.getOutputStream();
//把当前时间转成byte写入响应
out.write(new Date().toString().getBytes());
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
- 客户端代码
package cn.edu360.zk.gwtest;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.Watcher.Event.KeeperState;
public class Client {
//定义一个list 存放正在运行的服务器
private volatile ArrayList<String> onlineServers = new ArrayList<String>();
private ZooKeeper zk =null;
//获取 zookeeper的连接
public void getZKConn() throws Exception{
zk = new ZooKeeper("hdp01:2181,hdp02:2181,hdp03:2181", 2000, new Watcher() {
//重新监听进程
@Override
public void process(WatchedEvent event) {
// TODO Auto-generated method stub
//如果事件的状态=连接 且 事件的类型= 子节点变化 则重新或者online服务器
if (event.getState() == KeeperState.SyncConnected && event.getType() == EventType.NodeChildrenChanged) {
//调用 更新 onlineServers
try {
System.out.println("*******************检查到服务器更新*********************");
getOnlineServers();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
}
//查询在线服务器列表
public void getOnlineServers() throws Exception{
//获取 servers下的所有child
List<String> childrens = zk.getChildren("/Servers", true);
//这里需要新 new 一个list,然后复制后再覆盖 onlineServers
ArrayList<String> servers = new ArrayList<String>();
//循环所有child节点,
for (String child : childrens) {
//把服务器信息写入 onlineServers 中
byte[] data = zk.getData("/Servers/"+child, false, null);
servers.add(new String(data));
System.out.println("onlineServer更新"+new String(data));
}
onlineServers = servers;
}
//客户端请求方法
@SuppressWarnings("resource")
public void sendRequest() throws Exception{
//随机挑选一台服务器
Random random = new Random();
while(true){
int nextInt = random.nextInt(onlineServers.size());
String targetServer = onlineServers.get(nextInt);
System.out.println("本次的幸运儿服务器是:"+targetServer);
//获取服务器端 和 口号
String hostname = targetServer.split(":")[0];
String port = targetServer.split(":")[1];
//new 一个客户端
Socket socket = new Socket(hostname,Integer.parseInt(port));
//获取客户端的输入流与输出流
OutputStream outputStream = socket.getOutputStream();
InputStream inputStream = socket.getInputStream();
//客户端发送输出流 给服务器
outputStream.write("哥来发送请求了!".getBytes());
outputStream.flush();
//客户端获取服务器的输入流
byte[] buf = new byte[256];//定一个字符
int result = inputStream.read(buf);//把字符放到 buf 返回的 int对象为 读inputStream的结果
System.out.println("服务器响应状态:+"+ result +" 服务器响应的时间为:" + new String(buf, 0, result));
//一系列关闭
outputStream.close();
inputStream.close();
socket.close();
Thread.sleep(3000);
}
}
//主函数
public static void main(String[] args) throws Exception {
//new一个自己的对象(客户端)
Client client = new Client();
// 构造zk连接对象
client.getZKConn();
// 查询在线服务器列表
client.getOnlineServers();
// 处理业务(向一台服务器发送时间查询请求)
client.sendRequest();
}
}