Java之简单的聊天工具

Posted on 2013-07-25 18:28  冰天雪域  阅读(338)  评论(0编辑  收藏  举报

       今天整理资料的时候,找出自己几年前刚学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("测试");
	}
}


 


 

Copyright © 2024 冰天雪域
Powered by .NET 9.0 on Kubernetes