zoukankan      html  css  js  c++  java
  • Java之简单的聊天工具

           今天整理资料的时候,找出自己几年前刚学Java时做过的一个简易的聊天工具,有服务器也有客户端,能发送文字消息和文件,但是用户上线并未存入数据库,而只是简单的缓存在服务器的一个数组中,所以,只要服务器一关闭,所有用户数据都会消失,界面是用第三方包,很简单,有点丑陋,不喜勿喷。


    源码地址:http://download.csdn.net/detail/weidi1989/5810475

    GB2312编码方式,基于JDK1.7编译,如果直接导入eclipse出问题,请自行百度解决,3Q


    在运行代码之前,我们需要先作一下配置:

    ①服务器配置:如下图所示,找到Constants.java文件打开,将SERVER_IP改成你电脑对应的ip地址即可,端口视情况改变。


    ②客户端配置:同样如下图所示,找到Constants.java类,将SERVER_IP以及SERVER_PORT改成与服务器对应(这个很重要)


    ③先运行服务器,再运行客户端。



    下面,我们来看看具体效果图:

    1.先运行服务器,然后运行客户端,即可显示如下界面,同一局域网内的用户,会自动添加到好友列表中。



    2.测试文字聊天,只是简单发送文字消息,丑陋程度就不提了大笑



    3.测试文件发送与接收,发送的文件内容请忽视哦!



    简单的思路分析:

    ①服务器监听一个端口,时时等待用户的连接,当有用户上线时,经过几次握手成功,将该用户存入一个在线用户缓存器:UserCache。

    ②文字消息都是通过服务器转发的,用户首先将文字消息封装成一个对象(这个对象包含文字消息内容、来自哪里ip、发送给谁ip等),发送到服务器,服务器再从在线用户缓存器中遍历出要发送的对象ip,然后转发给该用户,即完成转发,跟我的Android之高仿手机QQ聊天是类似的。

    ③文件传输,是用户之间单独建立连接的,当一方要给另一方发送文件时,先通过服务器转发该文件大小、名称等信息,告知对方是否接收文件,如果对方接收,即启动一个监听文件传书的Socket,然后再回馈该信息(也是通过服务器转发)给另一方,此时启动一个线程Socket去连接对方发送文件(这中间,最好是加上超时判断,我这里很简单,就没有处理)。另外需要注意的是,我这里是通过SwingWorker来更新界面的,有点类似于Android的AsyncTask,做过Android的童鞋应该就很清楚了。


    由于是代码年代比较久远,也难免会有些细节会忘记,所以详细代码我就不给大家分析了,其实是很简单的,想学习一下的童鞋可以下载源码参考一下,下面我们来看看重要的两个部分代码:

    Server.java:

    /**
     * 服务器,接受用户登录、离线
     * 
     * @author way
     * 
     */
    public class Server {
    	private ServerSocket serverSocket = null;
    	private UserCache userCache = UserCache.getInstance();// 用户缓存器
    	private Transffer transffer = new TransfferImpl();
    
    	private boolean isStarted = true;
    
    	public Server() {
    		InetAddress address;
    		try {
    			address = InetAddress.getByName(Constants.SERVER_IP);
    			serverSocket = new ServerSocket(Constants.SERVER_PORT, 0, address);
    		} catch (UnknownHostException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    			System.exit(0);
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    			System.exit(0);
    		}
    	}
    
    	public void start() {
    		while (isStarted) {
    			try {
    				Socket socket = serverSocket.accept();
    				TranObject object = transffer.get(socket);
    				process(socket, object);
    			} catch (IOException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			} catch (ClassNotFoundException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    	}
    
    	/**
    	 * 对来自用户的请求进行处理
    	 * 
    	 * @param socket
    	 * @param object
    	 */
    	private void process(Socket socket, TranObject object) {
    		LLogger.info("接收到用户消息!");
    		switch (object.getType()) {
    		case LOGIN:
    			login(socket, object);
    			break;
    		case LOGOUT:
    			logout(socket, object);
    			break;
    		}
    	}
    
    	/**
    	 * 登录,登录完成后要向所有在线用户通报
    	 * @param socket
    	 * @param object
    	 */
    	private void login(Socket socket, TranObject object) {
    		LLogger.info("用户登录:" + object.getFromUser().getIp());
    		userCache.add(object.getFromUser());
    
    		TranObject<Set<User>> o = new TranObject<Set<User>>(
    				TranObjectType.LOGIN);
    		o.setToUser(object.getFromUser());
    		o.setObject(userCache.get());
    		try {
    			transffer.tran(socket, o);
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    		
    		//需要向所有用户发送该用户登录消息
    		TranObject<User> loginO = new TranObject<User>(TranObjectType.LOGIN);
    		loginO.setObject(object.getFromUser());
    		broadcast(loginO);
    	}
    
    	/**
    	 * 离线,离线完成后要向所有在线用户通报
    	 * @param socket
    	 * @param object
    	 */
    	private void logout(Socket socket, TranObject object) {
    		LLogger.info("用户离线:" + object.getFromUser().getIp());
    		userCache.delete(object.getFromUser());
    		
    		//需要向所有用户发送用户离线消息 
    		TranObject<User> logoutO = new TranObject<User>(TranObjectType.LOGOUT);
    		logoutO.setObject(object.getFromUser());
    		broadcast(logoutO);
    	}
    	
    	/**
    	 * 向所有在线用户发送广播包
    	 * 
    	 * @param object
    	 */
    	private void broadcast(TranObject object){
    		Set<User> set = userCache.get();
    		for(User u: set){
    			object.setToUser(u);
    			
    			try {
    				transffer.tranNoResponse(object);
    			} catch (IOException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			} catch (ClassNotFoundException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    	}
    
    	public static void main(String[] args) {
    		new Server().start();
    	}
    }
    


    下面是Client.java:

    /**
     * 客户端
     * 需要启动:
     * 1. 客户端消息服务器监听
     * 2. 消息处理器
     * 3. 登录并显示界面
     * 
     * @author way
     *
     */
    public class Client {
    	private User user = new User();
    	private ClientSender sender = ClientSenderImpl.getInstance();
    	private MessageProcessor messageProcessor = new MessageProcessor();//消息处理器
    	private ClientServer server;//消息监听器
    	
    	private MainFrame frame = new MainFrame(this);
    	private Cache cache = Cache.getInstance();
    	
    	public Client(String name){
    		user.setName(name);
    		user.setPort(Constants.CLIENT_SERVER_PORT);
    		
    		String ip = "";
    		try {
    			ip = getIp();
    		} catch (UnknownHostException e1) {
    			e1.printStackTrace();
    		}
    		if(ip==null
    				||ip.equals("")){
    			JOptionPane.showMessageDialog(null,"获取本机IP失败! ");
    			return;
    		}
    		
    		user.setIp(ip);
    		cache.setNowUser(user);
    		
    		if(!login()){
    			JOptionPane.showMessageDialog(null,"无法与服务器建立连接!");
    			return;
    		}
    		
    		/**
    		 * 启动消息处理器
    		 */
    		messageProcessor.execute();
    		
    		/**
    		 * 启动服务器
    		 */
    		try {
    			server = new ClientServer(frame,ip);
    			server.execute();
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    			JOptionPane.showMessageDialog(null, "端口已被占用,程序退出!");
    			System.exit(0);
    		}
    		
    		//显示主窗口 
    //		AWTUtilities.setWindowOpacity(frame, 1f);
    		frame.addWindowListener(new WindowListener(){
    
    			@Override
    			public void windowOpened(WindowEvent e) {
    				// TODO Auto-generated method stub
    				
    			}
    
    			@Override
    			public void windowClosing(WindowEvent e) {
    				
    			}
    
    			@Override
    			public void windowClosed(WindowEvent e) {
    				// TODO Auto-generated method stub
    				System.exit(0);
    			}
    
    			@Override
    			public void windowIconified(WindowEvent e) {
    				// TODO Auto-generated method stub
    				
    			}
    
    			@Override
    			public void windowDeiconified(WindowEvent e) {
    				// TODO Auto-generated method stub
    				
    			}
    
    			@Override
    			public void windowActivated(WindowEvent e) {
    				// TODO Auto-generated method stub
    				
    			}
    
    			@Override
    			public void windowDeactivated(WindowEvent e) {
    				// TODO Auto-generated method stub
    				
    			}
    			
    		});
    		frame.setVisible(true);
    	}
    	
    	private String getIp() throws UnknownHostException{
    		String ip = InetAddress.getLocalHost().getHostAddress();
    		return ip;
    	}
    	
    	/**
    	 * 退出操作
    	 * @return
    	 */
    	public void logout(){
    		LLogger.info("用户退出登录!");
    		sender.logout();
    	}
    	
    	/**
    	 * 登录 
    	 */
    	private boolean login(){
    		try {
    			Set<User> userSet = null;
    			userSet = sender.login();
    			frame.getCenterPanel().addUser(userSet);
    			return true;
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (ClassNotFoundException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    		return false;
    	}
    	
    	public static void main(String[] args){
    		UIManager.put("swing.boldMetal", Boolean.FALSE);
    		
    		new Client("测试");
    	}
    }
    



  • 相关阅读:
    java中BigDecimal的四舍五入小记
    thinking in java学习笔记:14章 类型信息
    java中==和equals
    java中值传递和引用传递
    java中的赋值
    hessian学习笔记
    springboot学习笔记:12.解决springboot打成可执行jar在linux上启动慢的问题
    要是满足下面的其中3种情况,你就跑路吧
    vim程序编辑器---常用操作整理
    报错end Kernel panic
  • 原文地址:https://www.cnblogs.com/aukle/p/3214992.html
Copyright © 2011-2022 走看看