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("测试");
    	}
    }
    



  • 相关阅读:
    To select the file to upload we can use the standard HTML input control of type
    Cascading Menu Script using Javascript Explained
    网站首页head区代码规范
    轻松掌握 Java 泛型
    JDK 5.0 中的泛型类型学习
    如何在firefox下获取下列框选中option的text
    是同步方法还是 synchronized 代码? 详解多线程同步规则
    javascript select option对象总结
    Select的动态取值(Text,value),添加,删除。兼容IE,FireFox
    javascript在ie和firefox下的一些差异
  • 原文地址:https://www.cnblogs.com/aukle/p/3214992.html
Copyright © 2011-2022 走看看