基于Android的简单聊天工具-服务器端

Posted fankongkong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于Android的简单聊天工具-服务器端相关的知识,希望对你有一定的参考价值。

1、数据库用的mysql,一共有3张表,一张用户表user、一张朋友列表friend和一张消息表message。

1 User table      用户表
  uid             主键自动生成
  userName        昵称
  userPwd         密码
  userSex         性别
  userPho         用户头像,有默认头像
2 Friend table    好友列表
  fid             主键自动生成
  uid --> fk      用户id,外键
  fuid -->        朋友的id
  fName           好友名称 
3 Messages table           消息表
  mid                      消息id,主键自动生成
  fromid --> fk from id    发送者id
  tofid --> fk to id       接收者id
  msg                      消息内容
  mtime                    发送时间

2、服务器端架构

3、model包解析

public class User{//1 用户类
    private String userName;//用户名
    private String userPwd;//用户密码
    private String userSex;//用户性别
    private String userPho;//用户照片
...
public class Friend {//2 朋友类
    private int uid;//用户id
    private int fuid;//friend id
    private String fName;//用户的朋友名字
...
public class FriendList extends ArrayList<Friend>{//3 朋友列表类
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private  FriendList friendlist;
    public FriendList() {
        friendlist = null;
    }
}
public class Messages{//4 消息类
    private int fromId;
    private int toId;
    private String msg;
    private String mtime;
    public Messages() {
        
    }

4、db包解析  

主要作用是加载类,获取mysql数据库的连接

public class DBConnection {
	public static final String DBURL = "jdbc:mysql://localhost:3306/qq";
	public static final String DBUSER = "root";
	public static final String DBPASS = "root";
	public static final String DBDRIVER = "com.mysql.jdbc.Driver";
	
	static {
		try {
			Class.forName(DBDRIVER);//加载类
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	//返回Connection
	public Connection getConnect() throws SQLException{
		return DriverManager.getConnection(DBURL,DBUSER,DBPASS);
	}
	//关闭资源
	public void close(Connection con, Statement sta, ResultSet rs) {
		try {
			rs.close();
			if(con != null) {
				con.close();
			}
			if(sta != null) {
				sta.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

5、util包解析

第一个类Packager

public class Packager {
	//用于登录数据包的分析
	public String loginPackager(String operate,String friends,String result) {
		StringBuffer mes = new StringBuffer("");
		mes.append("operate:" + operate + "\\n");
		mes.append("content:" + friends);
		mes.append("result:" + result + "\\n");
		return mes.toString();
	}
	//用于发送数据包的分析
	public String sendPackager(String operate,String msg,String result) {
		StringBuffer mes = new StringBuffer("");
		mes.append("operate:" + operate + "\\n");
		mes.append("content:" + "\\n");
		mes.append("result:" + result + "\\n");
		return mes.toString();
	}
}

第二个类Parser

public class Parser {
	//解析类
		//用于解析获取的请求类型是什么,比如登录、发送消息
	public String getOperate(String request) {
		String[] message = request.split("\\n");
		String operate = message[0].substring(8,message[0].length());
		return operate;
	}
	//获取内容
	public String getContent(String request) {
		String[] message = request.split("\\n");
		String content = message[1].substring(8,message[1].length());
		return content;
	}
	//获取发送的消息
	public Messages parseMessages(String content) {
		String[] mes = content.split("#");
		int toId = Integer.parseInt(mes[0]);
		String message = mes[1];
		Messages msg = new Messages();
		msg.setToId(toId);
		msg.setMsg(message);
		return msg;
	}
	//将字符串解析为用户类,返回用户类
	public User parseUser(String content) {
		//分隔符为#
		String[] mes = content.split("#");
		//第一个是用户名,第二个是密码
		String userName = mes[0];
		String userPwd = mes[1];
		User user = new User();
		user.setUserName(userName);
		user.setUserPwd(userPwd);
		return user;
	}
}

  

6、controll包解析

controller类解析

//控制器
public class Controller {
	//无参构造函数
	public Controller() {
		
	}
	//相应请求
	public String doResponse(String request,String ip) {
		Parser parser = new Parser();
		String operate = parser.getOperate(request);//用于解析用户的请求操作是什么
		String content = parser.getContent(request);//获取请求的内容
		String response = null;//相应字符串
		String friends = null;//朋友
		if("login".equals(operate)) {//判断是否是登录请求
			int  uid = login(content);//返回该用户的id,如果没有该用户返回0
			String result = null;
			if(uid != 0) {
				//将该用户的主键和ip地址加入管理客户端类中
				ManageClients.addIps(new Integer(uid), ip);
				result = "success";//如果登陆成功,那么获得该用户的所有朋友列表
				friends = getFriends(uid);
			}else{
				result = "fail";//登录失败
			}
			Packager packager = new Packager();
			response = packager.loginPackager(operate,friends,result);
		}else if("sendMessage".equals(operate)) {//如果是发送消息
			Messages msg = parser.parseMessages(content);
			int toId = msg.getToId();//找到要接受者的id
			String ipaddress = ManageClients.ips.get(new Integer(toId)).toString();//通过id 获得ip地址
			ServerThread sendto = (ServerThread)ManageClients.clients.get(ipaddress);//通过ip地址获取接受者的线程
			sendto.send(msg.getMsg());//向发送端发送信息
			Packager packager = new Packager();
			String result = "success";
			response = packager.sendPackager(operate,null,result);
		}
		return response;
	}
	public String getFriends(int uid) {
		String sql = "select fid,uid,fuid,fName from friend where uid=" + uid;
		DBConnection dbc = new DBConnection();
		Connection con = null;
		Statement sta = null;
		ResultSet rs = null;
		StringBuilder sb = new StringBuilder("");
		try {
			con = dbc.getConnect();
			con = dbc.getConnect();
			sta = con.createStatement();
			rs = sta.executeQuery(sql);
			while(rs.next()) {
			sb.append(rs.getInt(1)+"#" + rs.getInt(2) + "#" + rs.getInt(3) + "#" + rs.getString(4) + "\\n");
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return sb.toString();
	}
	public int login(String content) {//登录操作,登陆成功,返回朋友列表,否则返回错误原因
		Parser parser = new Parser();
		User user = parser.parseUser(content);//获取用户类
		//然后去数据库中查询是否有该用户,如果有该用户,那么返回该用户的主键id
		String sql = "select uid,userPwd from user where userName=\'" + user.getUserName() +"\'";
		DBConnection dbc = new DBConnection();
		Connection con = null;
		Statement sta = null;
		ResultSet rs = null;
		String dbpwd = null;
		int uid = 0;
		try {
			con = dbc.getConnect();
			sta = con.createStatement();
			rs = sta.executeQuery(sql);
			while(rs.next()) {
				uid = rs.getInt(1);
				dbpwd = rs.getString(2);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			dbc.close(con, sta, rs);
		}
		if(dbpwd != null && dbpwd.equals(user.getUserPwd()) && uid != 0) {
			return uid;
		}else{
			uid = 0;
			return uid;
		}
	}

7、server包解析

7.1 Server类 开启监听端口,不断监听请求的用户

public class Server {
	public static void main(String[] args) {
		new Server();
	}
	public Server()
	{
		ServerSocket serversocket = null;
		Socket socket = null;
			try {
				serversocket = new ServerSocket(5000);
				System.out.println("服务器已经启动,正在监听5000端口");
				while(true) {
					 socket = serversocket.accept();
					 String ip = socket.getLocalAddress().getHostAddress();
					 ServerThread st = new ServerThread(socket,ip);//服务器端线程
					 st.start();
					 ManageClients.addClients(ip, st);//将该线程添加到ManageClients类中
					 int port = socket.getPort();
					 System.out.println("连接上的客户端ip:" + ip + ",端口号:" + port);
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		
	}
}

7.2 ServerThread类 ,用于转发消息

public class ServerThread extends Thread{
	private Socket socket;
	private String ip;
	private InputStream in;
	private OutputStream out;
	private static final int SIZE = 1024;
	public Socket getSocket(){
		return socket;
	}
	public ServerThread(Socket socket,String ip) {
		this.socket = socket;
		this.ip = ip;
		try {
			in = socket.getInputStream();
			out = socket.getOutputStream();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	public void send(String mes) {
		try {
			out.write(mes.getBytes());
			out.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	public void close() {
			try {
				if(in != null){
					in.close();
					in = null;
				}
				if(out != null) {
					out.close();
					out = null;
				}
				if(socket != null) {
					socket.close();
					socket = null;
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
	}
	public void run() {
		while(true) {
			try {
				byte[] buffer = new byte[SIZE];
				int index = in.read(buffer);
				String message = new String(buffer,0,index);//获取客户端发送过来的请求
				Parser parser = new Parser();
				String operate = parser.getOperate(message);
				Controller controller = new Controller();
				if(operate.equals("exit")) {
					break;
				}
				
				String response = controller.doResponse(message,ip);//服务器处理发送过来的消息,如果不是收获
				//的操作不是exit
				if(response != null)
					send(response);//向客户端发送请求操作的结果
			} catch (IOException e) {
				e.printStackTrace();
			}finally{
				close();
			}
		}
		
	}

7.3 ManageClients

public class ManageClients {
	//管理客户端 ,用HashMap存储用户ip和线程的键值对
	public   static HashMap<String,ServerThread> clients = new HashMap<String,ServerThread>();//string sender
	//用于用户主键 和ip之间的键值对
	public  static HashMap<Integer,String> ips = new HashMap<Integer,String>();
	public static  void addClients(String senderip, ServerThread st) {
		clients.put(senderip, st);
	}
	public static void addIps(Integer i, String ip) {
		ips.put(i, ip);
	}
}

服务器端结束 ,启动Server中的main 函数,监听是否有客户端请求

 

以上是关于基于Android的简单聊天工具-服务器端的主要内容,如果未能解决你的问题,请参考以下文章

基于Socket的Android聊天室

基于Netty的简单多人聊天程序(服务端)

一天时间用OpenFire打造自己的IM聊天工具

Java案例:基于TCP的简单聊天程序

如何在Android系统下开发一个聊天软件?

基于Socket的Android聊天室