java-简单的聊天系统

      服务器端:

package chatSystem;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;

/**
 * Service : 服务器端
 * 
 * @author xuejupo [email protected] create in 2015-12-14 下午3:21:13
 */

public class Service {
	private InetSocketAddress socketAddress = null; // 服务监听地址
	private DatagramSocket datagramSocket = null; // 连接对象
	// 所有用户的连接端口
	private static Map<Integer, Integer> chatUsers = new HashMap<Integer, Integer>();
	// 服务器端的端口
	private static int port = 80;

	public void init() {
		socketAddress = new InetSocketAddress("localhost", port);
		System.out.println("--------服务器端已启动---------");
		try {
			datagramSocket = new DatagramSocket(socketAddress);
		} catch (SocketException e) {
			e.printStackTrace();
		}
		byte[] buffer = new byte[1024]; // 缓冲区
		while (true) {
			DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
			receive(packet);
			this.manage(packet);
		}
	}

	public static void main(String[] s) {
		Service ss = new Service();
		ss.init();
	}

	/**
	 * manage: 管理方法 规定获取的byte数组各位的意义: 第0位是状态位,除用户登录状态,第1位和第2位表示用户id
	 * 
	 * @param packet
	 *            void 返回类型
	 */
	private void manage(DatagramPacket packet) {
		byte[] info = packet.getData();
		// 状态为1表示登录
		// 状态为1时,1到18位表示用户的username(18位),19到40位表示用户的密码(22位)
		if (info[0] == 49) {
			int logStatus = this.log(info);
			if (logStatus != -1) {
				this.loginSuccess(packet, logStatus);
			} else {
				this.loginFalse(packet);
			}
		} else if (info[0] == 48) {
			// 状态为0表示退出
			// 将是否在线状态置为false
			Storage.onLineUsers.set(getUserId(info), false);
			System.out.println("用户"+Storage.ID_NAME.get(getUserId(info))+"退出!");
			// 从群聊天里去掉
			chatUsers.remove(this.getUserId(info));
			return;
		} else if (info[0] == 50) {
			// 状态为2表示发送群消息
			String userName = Storage.ID_NAME.get(this.getUserId(info));
			String msg = this.getInfo(info, 3).trim();
			System.out.println(userName+"对大家说:"+msg);
			this.sendAll(packet, userName, msg);
		} else if (info[0] == 51) {
			// 状态为3表示发送个人消息
			// 当状态为3时,第4位第5为表示目标用户id
			this.send(this.potPacket(info, packet));
		}
	}

	/**
	 * potPacket: 发送私人消息时,封装发送数据包
	 * 
	 * @return DatagramPacket 返回类型
	 */
	private DatagramPacket potPacket(byte[] info, DatagramPacket packet) {
		String userName = Storage.ID_NAME.get(this.getUserId(info));
		int toUserId = this.getToUserId(info);
		String msg = this.getInfo(info, 5);
		byte[] messageByte = this.getBytes(userName + "对你说:" + msg);
		packet.setData(messageByte);
		packet.setLength(messageByte.length);
		try {
			packet = new DatagramPacket(messageByte, messageByte.length,
					InetAddress.getByName("localhost"), chatUsers.get(toUserId));
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(userName+"对"+Storage.ID_NAME.get(toUserId)+"说:"+msg);
		return packet;
	}

	/**
	 * getInfo: 获取byte数组中的string消息offset 起始位置,当群发消息时,起始位置应该是3,当发送私人消息时,起始位置应该是5
	 * 
	 * @return String 返回类型
	 */
	private String getInfo(byte[] info, int offset) {
		String s = new String(info);
		byte[] infoB = new byte[info.length - offset];
		System.arraycopy(info, offset, infoB, 0, info.length - offset);
		return new String(infoB).trim();
	}

	/**
	 * log: 登录方法
	 * 
	 * @param info
	 *            传过来的包所包含的信息
	 * @return boolean 返回类型
	 */
	private int log(byte[] info) {
		byte[] nameB = new byte[18];
		byte[] passwdB = new byte[22];
		System.arraycopy(info, 1, nameB, 0, 18);
		System.arraycopy(info, 19, passwdB, 0, 22);
		return LoginModule.login(new String(nameB).trim(), new String(passwdB).trim());
	}

	/**
	 * loginSuccess: 登录成功后的处理方法
	 * 
	 * @param packet
	 *            void 返回类型
	 */
	private void loginSuccess(DatagramPacket packet, int userid) {
		byte[] message = getBytes("登录成功");
		packet.setData(message);
		packet.setLength(message.length);
		this.send(packet);
		// 将登录成功的客户端端口加入到群聊天端口
		chatUsers.put(userid, packet.getPort());
		System.out.println("用户"+Storage.ID_NAME.get(userid)+"登录成功");
	}

	/**
	 * loginFalse: 登录失败后的处理方法
	 * 
	 * @param packet
	 *            void 返回类型
	 */
	private void loginFalse(DatagramPacket packet) {
		byte[] message = getBytes("登录失败");
		packet.setData(message);
		packet.setLength(message.length);
		this.send(packet);
		System.out.println("登录失败");
	}

	/**
	 * getBytes: 获取字符串的byte数组表示
	 * 
	 * @param msg
	 *            void 返回类型
	 */
	private byte[] getBytes(String msg) {
		return msg.getBytes();
	}

	/**
	 * getUserId: 获取用户id
	 * 
	 * @param b
	 * @return int 返回类型
	 */
	private int getUserId(byte[] b) {
		byte[] id = new byte[2];
		id[0] = b[1];
		id[1] = b[2];
		String idStr = new String(id).trim();
		return Integer.parseInt(idStr);
	}

	/**
	 * getUserId: 发送私人消息时,获取目的用户id
	 * 
	 * @param b
	 * @return int 返回类型
	 */
	private int getToUserId(byte[] b) {
		byte[] id = new byte[2];
		id[0] = b[3];
		id[1] = b[4];
		String idStr = new String(id).trim();
		return Integer.parseInt(idStr);
	}

	/**
	 * receive: 接收数据包
	 * 
	 * @param packet
	 * @return
	 * @throws Exception
	 *             DatagramPacket 返回类型
	 */
	public DatagramPacket receive(DatagramPacket packet) {
		try {
			datagramSocket.receive(packet);
		} catch (Exception e) {
			System.out.println(e.getLocalizedMessage());
		}
		return packet;
	}

	/**
	 * 将信息发送给客户端 response:
	 * 
	 * @param packet
	 *            void 返回类型
	 */
	public void send(DatagramPacket packet) {
		try {
			datagramSocket.send(packet);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * sendAll: 将信息发给所有的在线客户端
	 * 
	 * @param packet
	 *            void 返回类型
	 */
	private void sendAll(DatagramPacket packet, String username, String msg) {
		byte[] info = (username + "说:" + msg).getBytes();
		for (int iaddr : chatUsers.values()) {
			try {
				packet = new DatagramPacket(info, info.length,
						InetAddress.getByName("localhost"), iaddr);
			} catch (UnknownHostException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			this.send(packet);
		}
	}
}

 客户端:

package chatSystem;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;

/**
 * Client :
 * 
 * @author xuejupo [email protected] create in 2015-12-14 下午3:47:37
 */

public class Client extends Thread {
	private static final int PORT = 80;
	private DatagramSocket dataSocket;
	private DatagramPacket dataPacket;
	private String sendStr;
	private int clinePort;
	private String name;
	private String id;
	private String toId;
	public Client(int port,String name,String id,String toId){
		this.clinePort = port;
		this.name = name;
		this.id = id;
		this.toId = toId;
	}

	public void run() {
		new receiveThread().start();
		this.init();
	}

	public void init() {
		try {
			// 指定端口号,避免与其他应用程序发生冲突
			dataSocket = new DatagramSocket(clinePort);
			System.out.println("用户登录----");
			this.log(this.name, "123456");
			Thread.sleep(1000);
			System.out.println("发送群消息----");
			Thread.sleep(1000);
			this.sendAll();
			System.out.println("发送私人消息");
			Thread.sleep(1000);
			this.sendPrient();
		} catch (SocketException se) {
			se.printStackTrace();
		} catch (IOException ie) {
			ie.printStackTrace();
		} catch(Exception e){
			e.printStackTrace();
		}
	}

	/**
	 * log: 登录
	 * 
	 * @param username
	 * @param pwd
	 *            void 返回类型
	 */
	public void log(String username, String pwd) {
		byte[] name = this.getLenthBytes(username, 18);
		byte[] passwd = this.getLenthBytes(pwd, 22);
		byte[] message = new byte[44];
		message[0] = 49;
		System.arraycopy(name, 0, message, 1, 18);
		System.arraycopy(passwd, 0, message, 19, 22);
		this.send(message);
	}

	/**
	 * getLenthBytes: 获得定长的byte数组
	 * 
	 * @return byte[] 返回类型
	 */
	private byte[] getLenthBytes(String msg, int length) {
		byte[] result = msg.getBytes();
		byte[] returnByte = new byte[length];
		if (result.length == length) {
			return result;
		}
		for (int i = 0; i < length; i++) {
			if (i < result.length) {
				returnByte[i] = result[i];
			} else {
				returnByte[i] = ' ';
			}
		}
		return returnByte;
	}

	/**
	 * sendDate: 发送数据包
	 * 
	 * @param packet
	 *            void 返回类型
	 */
	public void sendDate(DatagramPacket packet) {
		try {
			dataSocket.send(packet);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * sendDate: 发送群消息
	 * 
	 * @param packet
	 *            void 返回类型
	 */
	public void sendAll() {
		String msg = "我是"+this.name;
		byte[] msgByte = new byte[msg.getBytes().length + 3];
		msgByte[0] = 50;
		System.arraycopy(this.id.getBytes(), 0, msgByte, 1, 2);
		System.arraycopy(msgByte, 0, msgByte, 3, msg.getBytes().length);
		try {
			dataPacket = new DatagramPacket(msgByte, msgByte.length,
					InetAddress.getByName("localhost"), PORT);
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		this.sendDate(dataPacket);
	}
	
	/**
	 * sendDate: 发送私人消息
	 * 
	 * @param packet
	 *            void 返回类型
	 */
	public void sendPrient() {
		String msg = "我是"+this.name;
		byte[] msgByte = new byte[msg.getBytes().length + 5];
		msgByte[0] = 50;
		System.arraycopy(this.id.getBytes(), 0, msgByte, 1, 2);
		System.arraycopy(this.toId.getBytes(), 0, msgByte, 3, 2);
		System.arraycopy(msgByte, 0, msgByte, 5, msg.getBytes().length);
		try {
			dataPacket = new DatagramPacket(msgByte, msgByte.length,
					InetAddress.getByName("localhost"), PORT);
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		this.sendDate(dataPacket);
	}

	/**
	 * send: 发送数据包
	 * 
	 * @param packet
	 *            void 返回类型
	 */
	public void send(byte[] msg) {
		try {
			dataPacket = new DatagramPacket(msg, msg.length,
					InetAddress.getByName("localhost"), PORT);
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		this.sendDate(dataPacket);
	}

	/**
	 * sendDate: 接收数据包
	 * 
	 * @param packet
	 *            void 返回类型
	 */
	public void receive(DatagramPacket packet) {
		try {
			dataSocket.receive(packet);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// 接收服务器端数据的线程
	class receiveThread extends Thread {
		public void run() {
			byte[] sendDataByte = new byte[10000];
			try {
				dataPacket = new DatagramPacket(sendDataByte,
						sendDataByte.length,
						InetAddress.getByName("localhost"), PORT);
			} catch (UnknownHostException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			while (true) {
				receive(dataPacket);
				System.out.println(new String(dataPacket.getData()).trim());
			}
		}
	}
}

 存储端:

package chatSystem;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import jxl.Cell;
import jxl.Sheet;
import jxl.Workbook;
import jxl.read.biff.BiffException;

/**
 * Storage :
 * 
 * @author xuejupo [email protected] create in 2015-12-14 上午10:59:01
 */

public class Storage {
	private static Storage single = new Storage();

	// 构造函数设为私有
	private Storage() {
	}

	// 单例模式
	public static Storage getSingle() {
		return single;
	}

	// 存储所有的用户信息(用户名-key,密码:value)
	public static Map<String, User> allUser = new ConcurrentHashMap<String, User>();
	// 存储所有的用户信息(用户名-key,密码:value)
	public static Map<Integer, String> ID_NAME = new ConcurrentHashMap<Integer, String>();
	// 位图,存储所有的用户在线状态(二位数用户规模)
	public static BitSet onLineUsers = new BitSet(100);
	// 静态块,初始化静态信息
	static {
		File f = new File("D:\\gongjiao\\用户信息.xls");
		if (!f.exists()) {
			System.out.println("ERROR!!!");
		}
		try {
			Workbook book = Workbook.getWorkbook(f);//
			Sheet sheet = book.getSheet(0); // 获得第一个工作表对象
			for (int i = 0; i < sheet.getRows(); i++) {
				User user = new User();
				for (int j = 0; j < sheet.getColumns(); j++) {
					Cell cell = sheet.getCell(j, i); // 获得单元格
					String info = cell.getContents();
					if (j == 0) {
						user.setUserId(Integer.parseInt(info));
					} else if (j == 1) {
						user.setUserName(info);
					} else if (j == 2) {
						user.setUserName(info);
					} else if (j == 3) {
						user.setPasswd(info);
					} else if (j == 4) {
						user.setAge(Integer.parseInt(info));
					} else if (j == 5) {
						user.setSex(Integer.parseInt(info));
					} else if (j == 6) {
						user.setNoFriendChat("1".equals(info));
					} else if (j == 7) {
						List<String> userids = new ArrayList<String>();
						for (String userid : info.split(",")) {
							userids.add(userid);
						}
						user.setFriends(userids);
					} else if (j == 8) {
						List<String> userids = new ArrayList<String>();
						if (info != null && !"".equals(info.trim())) {
							for (String userid : info.split(",")) {
								userids.add(userid);
							}
						}
						user.setBlackList(userids);
					} else if (j == 9) {
						user.setDetail(info);
					} else if (j == 10) {
						user.setBlackNum(Integer.parseInt(info));
					}
				}
				ID_NAME.put(user.getUserId(), user.getUserName());
				allUser.put(user.getUserName(), user);
				user = new User();
			}
		} catch (BiffException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

 user类:

package chatSystem;

import java.util.List;

/**
 * User : 用户bean
 * 
 * @author xuejupo [email protected] create in 2015-12-14 下午1:28:31
 */

public class User {
	// 用户id
	private int userId;
	// 用户名
	private String userName;
	// 用户的真实姓名
	private String tureName;
	// 用户密码
	private String passwd;
	// 用户年龄
	private int age;
	// 用户的性别,1为男,2为女
	private int sex;
	// 用户是否接受非好友私人聊天
	private boolean noFriendChat;
	// 用户好友的id列表
	private List<String> friends;
	// 用户的黑名单列表
	private List<String> blackList;
	// 用户的简单描述
	private String detail;
	//标记该用户为黑名单的人数
	private int blackNum;
	
	public final int getBlackNum() {
		return blackNum;
	}

	public final void setBlackNum(int blackNum) {
		this.blackNum = blackNum;
	}

	public final int getUserId() {
		return userId;
	}

	public final void setUserId(int userId) {
		this.userId = userId;
	}

	public final String getUserName() {
		return userName;
	}

	public final void setUserName(String userName) {
		this.userName = userName;
	}

	public final String getTureName() {
		return tureName;
	}

	public final void setTureName(String tureName) {
		this.tureName = tureName;
	}

	public final String getPasswd() {
		return passwd;
	}

	public final void setPasswd(String passwd) {
		this.passwd = passwd;
	}

	public final int getAge() {
		return age;
	}

	public final void setAge(int age) {
		this.age = age;
	}

	public final int getSex() {
		return sex;
	}

	public final void setSex(int sex) {
		this.sex = sex;
	}

	public final boolean isNoFriendChat() {
		return noFriendChat;
	}

	public final void setNoFriendChat(boolean noFriendChat) {
		this.noFriendChat = noFriendChat;
	}

	public final List<String> getFriends() {
		return friends;
	}

	public final void setFriends(List<String> friends) {
		this.friends = friends;
	}

	public final List<String> getBlackList() {
		return blackList;
	}

	public final void setBlackList(List<String> blackList) {
		this.blackList = blackList;
	}

	public final String getDetail() {
		return detail;
	}

	public final void setDetail(String detail) {
		this.detail = detail;
	}
	
	public final void addFriend(String userName){
		this.friends.add(userName);
	}
	
	public final void addBlack(String userName){
		this.blackList.add(userName);
	}
	/**
	 * 重写tostring方法,用于展示用户信息
	 */
	public String toString() {
		return "name:" + this.tureName + "\tage:" + this.age + "\tsex:"
				+ (this.sex == 1 ? "MEN" : (this.sex == 2 ? "WOMEN" : "OTHER"))
				+ "\r\n" + "the detail:\r\n" + this.detail;
	}
}

 user操作公共类:

package chatSystem;

import java.util.List;

/**  
 *  UserUtil : 与用户相关的公共类
 * @author xuejupo  [email protected] 
 * create in 2015-12-15 下午5:50:20    
 */

public class UserUtil {
	/**  
	* getFriends: 获取用户的朋友列表
	* @param username
	* @return 
	* List<String>  返回类型   
	*/
	public static List<String> getFriends(String username){
		return Storage.allUser.get(username).getFriends();
	}
	
	/**  
	* getBlackList: 获取用户的黑名单列表
	* @param username
	* @return 
	* List<String>  返回类型   
	*/
	public static List<String> getBlackList(String username){
		return Storage.allUser.get(username).getBlackList();
	}
	
	/**  
	* isOnLine: 获取用户是否在线
	* @param username
	* @return 
	* boolean  返回类型   
	*/
	public static boolean isOnLine(String username){
		return Storage.onLineUsers.get(Storage.allUser.get(username).getUserId());
	}
}

         PS:没有界面的聊天系统实在是太不美观了。。。  聊天系统暂时先做到这,等自己能写客户端了(不管什么语言吧,至少要有客户端)再回头来把这个更新一下。注释很多,相信不难看懂。

         写这个系统的时候,用到一个单例模式,明天开始把设计模式结合代码实例好好看看。

猜你喜欢

转载自709002341.iteye.com/blog/2264369