Zookeeper客户端编程趣味小例子——网络聊天

本文介绍了一个基于Zookeeper实现的简单聊天室客户端程序。该程序能够显示在线用户、接收消息并监听用户登录登出事件。通过创建临时节点来标识在线状态,并利用Zookeeper的数据变更监听功能实现消息传递。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

共享一份闲暇之余编写的Zookeeper客户端使用的一些最基础的代码,下面实现的是一个网络聊天的小程序

需要将Zookeeper的服务器启动好了之后,修改其中的IP地址就可,可配置多个服务器IP

package yz.web;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.KeeperException.NodeExistsException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

public class AppClient implements Watcher, Runnable{  
    private String clientListNode = "/chat";  
    private ZooKeeper zk;  
    private Stat stat = new Stat();  
    private volatile List<String> onlineUsers = new ArrayList<String>();  
    private String myself = "";
    private CountDownLatch connectedSignal = new CountDownLatch(1);
  
    public void connectZookeeper() throws Exception {  
        zk = new ZooKeeper("192.168.20.97:2181,192.168.20.97:2182,192.168.20.97:2183,192.168.20.97:2184,192.168.20.97:2185", 5000, this);
        connectedSignal.await(); // 等待连接完成
        userLogin();
    }  

	private void userLogin() throws IOException, KeeperException, InterruptedException {
		showOnlineUsers();
		myself = inputName();
    	createNamePath(myself);
    	zk.getData(clientListNode, true, stat); // 注册NodeDataChanged事件的watcher
	}
	
	private void showOnlineUsers() throws KeeperException, InterruptedException {
		List<String> onlineUsers = zk.getChildren(clientListNode, true);
		if (onlineUsers.size() > 0) {
			System.out.println("The online users is shown as below:");
			for (String username : onlineUsers) {
				System.out.println(username);
				this.onlineUsers.add(username);
			}
		} else {
			System.out.println("No one is online!");
		}
	}

	private void createNamePath(String name) throws KeeperException, InterruptedException, IOException {
		try {
        	zk.create(clientListNode + "/" + name, null, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
        } catch (NodeExistsException e) {
        	System.out.println("The name is duplicated...");
        	userLogin();
        } catch (Exception e) {
        	System.out.println("Occur unexpected exception...");
        	userLogin();
        }
	}
	
	private String inputName() throws IOException {
		System.out.println("Please input your name:");
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    	String name = br.readLine();
		return name;
	}
  
	private String getLastPathName(String path) {
    	return path.substring(path.lastIndexOf("/") + 1, path.length());
	}
  
    public void handleChat() throws InterruptedException {  
        run();
        Thread.sleep(Long.MAX_VALUE);
    }  
  
    public void run() {
    	while (true) {
	    	try {
	    		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
				String chatContent = br.readLine();
				if (chatContent == null || "".equals(chatContent)) {
					continue;
				}
				zk.setData(clientListNode, (myself + " says: " + chatContent).getBytes("utf-8"), -1);
			} catch (Exception e) {
				e.printStackTrace();
			}
    	}
	}

	public void process(WatchedEvent event) {
        String path = event.getPath();
        if (event.getType() == Event.EventType.None) {
            // We are are being told that the state of the
            // connection has changed
            switch (event.getState()) {
            case SyncConnected:
                // In this particular example we don't need to do anything
                // here - watches are automatically re-registered with 
                // server and any watches triggered while the client was 
                // disconnected will be delivered (in order of course)
            	connectedSignal.countDown();// 倒数-1
                break;
            case Expired:
                // It's all over
                break;
			default:
				break;
            }
        } else {
        	if (event.getType() == EventType.NodeChildrenChanged && path.equals(clientListNode)) {
            	try {
    				checkUsers();
    			} catch (KeeperException e) {
    				e.printStackTrace();
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
            } else if (event.getType() == EventType.NodeDataChanged) {
            	try {
					String chatContent = new String(zk.getData(clientListNode, true, stat), "utf-8");
					System.out.println(chatContent);
				} catch (KeeperException e) {
					e.printStackTrace();
				} catch (InterruptedException e) {
					e.printStackTrace();
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
            }
        }
	}
	
	protected void checkUsers() throws KeeperException, InterruptedException {
		List<String> onlineUsers = zk.getChildren(clientListNode, true);
		int preUserNum = this.onlineUsers.size();
		int nowUserNum = onlineUsers.size();
		List<String> tempList = new ArrayList<String>(Arrays.asList(new String[this.onlineUsers.size()]));
		Collections.copy(tempList, this.onlineUsers);
		
		if (preUserNum == nowUserNum) {
			return;
		} else if (preUserNum > nowUserNum) {
			tempList.removeAll(onlineUsers);
			someoneLogout(tempList);
		} else if (preUserNum < nowUserNum) {
			onlineUsers.removeAll(tempList);
			someoneLogin(onlineUsers);
		}
	}
    
	protected void someoneLogout(List<String> paths) {
		for (String path : paths) {
			String username = getLastPathName(path);
			if (onlineUsers.contains(username)) {
				System.out.println(username + " is logout...");
				onlineUsers.remove(username);
			}
		}
	}

	private void someoneLogin(List<String> paths) {
		for (String path : paths) {
			String username = getLastPathName(path);
			if (!onlineUsers.contains(username)) {
				System.out.println(username + " is login...");
				onlineUsers.add(username);
			}
		}
	}
	
    public static void main(String[] args) {  
    	try {
	        AppClient ac = new AppClient();  
	        ac.connectZookeeper();  
	        ac.handleChat();  
    	} catch(Exception e){
    		e.printStackTrace();
    	}
    }
}  


  	<dependency>
	    <groupId>org.apache.zookeeper</groupId>
	    <artifactId>zookeeper</artifactId>
	    <version>3.4.6</version>
	</dependency>



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值