diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ae3c172 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/lib/mysql-connector-java-5.1.44-bin.jar b/lib/mysql-connector-java-5.1.44-bin.jar new file mode 100644 index 0000000..2f2e32d Binary files /dev/null and b/lib/mysql-connector-java-5.1.44-bin.jar differ diff --git a/src/com/wecheer/server/Server.java b/src/com/wecheer/server/Server.java new file mode 100644 index 0000000..9438e12 --- /dev/null +++ b/src/com/wecheer/server/Server.java @@ -0,0 +1,323 @@ +package com.wecheer.server; + +import java.io.*; +import java.util.*; + +import com.wecheer.simpleprotx.Spx; + +import java.net.*; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.text.SimpleDateFormat; + +public class Server extends Thread implements Spx{ + private static boolean StartServer = true; + private static Vector PrintWriterRecord = new Vector(); + private static Vector UnameOn = new Vector(); + private static Map Mouth = new HashMap(); + private static Map UserOn = new HashMap(); + public static final transient Object NotBusy = new Object(); + public static final transient Object Semaphore = new Object(); + + private Socket socket; + private Boolean isRunning = false; + + public Server(Socket ClientSocket) { + this.isRunning = true; + this.socket = ClientSocket; + } + + public void send(PrintWriter output, String str) { + synchronized(Server.NotBusy) { + output.println(str); + output.flush(); + } + } + + public void addUser(String uid, String uname, PrintWriter pw) { + synchronized(Server.Semaphore) { + Mouth.put(uid, pw); + UserOn.put(pw, uid); + UnameOn.add(uname); + PrintWriterRecord.add(pw); + } + } + + public void removeUser(String uid, String uname, PrintWriter pw) { + synchronized(Server.Semaphore) { + Mouth.remove(uid); + PrintWriterRecord.remove(pw); + UnameOn.removeElement(uname); + UserOn.remove(pw); + } + } + + public void broadcast(String str) throws IOException { + for (int i = 0; i < PrintWriterRecord.size(); i++) { + PrintWriter pw = PrintWriterRecord.get(i); + send(pw, PUBLIC_MESSAGE + str); + } + } + + public String lookForOnlineUsers(String currentuser) { + String others = currentuser; + for (int i = 0; i < UnameOn.size(); i++) { + String other = UnameOn.get(i); + if (null == other || other.equals(currentuser)) + continue; + others = others + _SEMICOLON + other; + } + return others; + } + + public void broadcastOnlineUsers(String str) throws IOException { + for (int i = 0; i < PrintWriterRecord.size(); i++) { + PrintWriter pw = PrintWriterRecord.get(i); + send(pw, PUBLIC_USERS_ONLINE + str); + } + } + + public void lanDiscoveryBroadcast(String currentuser, String comego) { + try { + broadcast(currentuser + comego + "。 总在线人数:" + PrintWriterRecord.size()); + } catch (IOException e1) {} + String others = "......"; + for (int i = 0; i < UnameOn.size(); i++) { + String other = UnameOn.get(i); + if (comego.equalsIgnoreCase(_COME)) + others = others + _SEMICOLON + other; + else if (!other.equals(currentuser)) + others = others + _SEMICOLON + other; + } + try { + broadcastOnlineUsers(others); + } catch (IOException e) {} + } + + public void run() { + try { + Connection conn = null; + try { + Class.forName ("com.mysql.jdbc.Driver"); + conn = DriverManager.getConnection( + WECHEER_DATABASE_NAME, + WECHEER_DATABASE_ROOT_NAME, + WECHEER_DATABASE_ROOT_KEY + ); + } catch (ClassNotFoundException e) {} catch (SQLException se) {} + System.out.println(socket.toString()); + final BufferedReader currentbr = new BufferedReader(new InputStreamReader(socket.getInputStream())); + final PrintWriter currentpw = new PrintWriter(socket.getOutputStream()); + + final String connapply = currentbr.readLine(); + final String userinfo = new String(connapply); + final String applyprefix = connapply.length() <= 9 ? connapply : connapply.substring(0, 10); + if (applyprefix.equals(SIGN_UP)) { + final String newinfo = connapply.length() <= 9 ? connapply : connapply.substring(10, connapply.length()); + String[] strs = newinfo.split(_COMMA); + final String currentuid = strs[0]; + final String currentuser = strs[1]; + final String currentcode = strs[2]; + PreparedStatement p = conn.prepareStatement(JDBC_INSERT_USERINFO); + p.clearParameters(); + p.setString(1, currentuid); + p.setString(2, currentuser); + p.setString(3, currentcode); + p.executeUpdate(); + p.close(); + } // if SIGN_UP + else { + final String currentuid = userinfo.length() <= 9 ? userinfo : userinfo.substring(0, 10); + final String currentcode = userinfo.substring(currentuid.length(), userinfo.length()); + String refuser = "0000000000"; + String refcode = "0000000000"; + PreparedStatement p0 = conn.prepareStatement(JDBC_UID_EXISTS); + p0.clearParameters(); + p0.setString(1, currentuid); + ResultSet r0 = p0.executeQuery(); + if (r0.next()) { + refuser = r0.getString(1); + p0 = conn.prepareStatement(JDBC_CORRESPONDED_KEY); + p0.clearParameters(); + p0.setString(1, refuser); + ResultSet r1 = p0.executeQuery(); + if (r1.next()) { + refcode = r1.getString(1); + if (currentcode.equals(refcode)) { + while (UserOn.containsValue(currentuid)) { + PrintWriter exprintwriter = Mouth.get(currentuid); + send(exprintwriter, null); + PreparedStatement p = conn.prepareStatement(JDBC_WHOAMI); + p.setString(1, currentuid); + ResultSet r = p.executeQuery(); + String formeruser = ""; + if (r.next()) + formeruser = r.getString(1); + removeUser(currentuid, formeruser, exprintwriter); + } + send(currentpw, "portnum" + Integer.toString(socket.getLocalPort())); + } else send(currentpw, "密码错误"); + } + } else send(currentpw, "未注册"); + + String ulookup = currentbr.readLine(); + String currentuser = ""; + if (ulookup.equalsIgnoreCase(WHO_AM_I)) { + PreparedStatement p = conn.prepareStatement(JDBC_WHOAMI); + p.setString(1, currentuid); + ResultSet r = p.executeQuery(); + if (r.next()) + currentuser = r.getString(1); + addUser(currentuid, currentuser, currentpw); + send(currentpw, currentuser + _QMARK + lookForOnlineUsers(currentuser)); + } + + ulookup = currentbr.readLine(); + if (ulookup.equalsIgnoreCase(WHO_ARE_MY_FRIENDS)) { + PreparedStatement p = conn.prepareStatement(JDBC_WHOARE_MYFRIENDS); + p.clearParameters(); + p.setString(1, currentuid); + ResultSet r11 = p.executeQuery(); + String friends = ""; + while (r11.next()) { + friends = friends + r11.getString(1) + _COMMA + r11.getString(2) + _SEMICOLON; + } + send(currentpw, friends); + } + + lanDiscoveryBroadcast(currentuser, "来了"); + + /* 聊天转发 */ + while (Server.StartServer && this.isRunning) { + // readline + String str = null; + try { + str = currentbr.readLine(); + } catch (IOException e) { + this.isRunning = false; + continue; + } catch (NullPointerException n) { + this.isRunning = false; + continue; + } + final String tstr = str; + final String prefix = tstr.length() < 10 ? "illegal" : tstr.substring(0, 10); + + // 转发公共消息 + if (prefix.equals(PUBLIC_MESSAGE)) { + String bodies = tstr.substring(10, tstr.length()); + synchronized (Server.NotBusy) { + try { + broadcast(currentuser + ":" + bodies); + } catch (IOException e) {} + System.out.println(currentuser + ":" + bodies); + } + } + + // 转发建立私聊请求 + else if (prefix.equals(PRIVATE_CONNECTION_REQUEST)) { + String targetuid = tstr.substring(10, tstr.length()); + if (targetuid.startsWith("暂时没有好友")) { + send(currentpw, PRIVATE_PARTY_OFFLINE + "你暂时还没有好友。快去添加好友吧。"); + } + else if (Mouth.containsKey(targetuid)) { + synchronized (Server.NotBusy) { + PrintWriter targetpw = Mouth.get(targetuid); + send(targetpw, PRIVATE_CONNECTION_ENQUEST + currentuid); + send(currentpw, PRIVATE_CONNECTION_ENQUEST + targetuid); + } + System.out.println(currentuser + " and " + targetuid + " has connected."); + } + else { + send(currentpw, PRIVATE_PARTY_OFFLINE + "对方不在线"); + } + } + + // 转发私人消息 + else if (prefix.equals(PRIVATE_MESSAGE)) { + String targetuid = tstr.substring(10, 20); + String bodies = tstr.substring(20, tstr.length()); + if (Mouth.containsKey(targetuid)) { + synchronized (Server.NotBusy) { + PrintWriter targetpw = Mouth.get(targetuid); + send(targetpw, PRIVATE_MESSAGE + currentuid + currentuser + ":" + bodies); + } + System.out.println(currentuser + " privately talked to " + targetuid + ":" + bodies); + } + } + + else if (prefix.equals(PRIVATE_PICTURE)) { + String targetuid = tstr.substring(10, 20); + String bodies = tstr.substring(20, tstr.length()); + if (Mouth.containsKey(targetuid)) { + synchronized (Server.NotBusy) { + PrintWriter targetpw = Mouth.get(targetuid); + send(targetpw, PRIVATE_PICTURE + currentuid + bodies); + } + System.out.println(currentuser + " privately sent a picture to " + targetuid); + } + } + + // 转发结束私聊请求 + else if (prefix.equals(PRIVATE_DISCONNECTION_REQUEST)) { + String targetuid = tstr.substring(10, 20); + if (Mouth.containsKey(targetuid)) { + synchronized (Server.NotBusy) { + PrintWriter targetpw = Mouth.get(targetuid); + send(targetpw, PRIVATE_DISCONNECTION_ENQUEST + currentuid); + } + } + System.out.println(currentuser + " has disconnected to " + targetuid); + } + } + removeUser(currentuid, currentuser, currentpw); + lanDiscoveryBroadcast(currentuser, _LEAVE); + currentpw.close(); + currentbr.close(); + socket.close(); + } // else SIGN_IN + } catch (IOException ex) {} catch (SQLException e) {} + } // Run user message processing thread + + public static void main(String[] args) throws IOException { + ServerSocket ServerSocket = new ServerSocket((args.length >= 1) ? Integer.parseInt(args[0]) : 9102); + KeyboardListener keyboardlistener = new KeyboardListener(PrintWriterRecord); + keyboardlistener.start(); + System.out.println("服务器已启动"); + while (StartServer) { + Socket socket = ServerSocket.accept(); + Server server = new Server(socket); + server.start(); + } + ServerSocket.close(); + } +} + +final class KeyboardListener extends Thread { + boolean StartKeyboardInput = true; + private Vector PrintWriterRecord; + + public KeyboardListener(Vector PrintWriterRecord) { + this.PrintWriterRecord = PrintWriterRecord; + } + + public void run() { + BufferedReader bufferedreader = new BufferedReader(new InputStreamReader(System.in)); + while (StartKeyboardInput) { + String str = null; + try { + str = bufferedreader.readLine(); + synchronized(Server.NotBusy) { + for (int i = 0; i < PrintWriterRecord.size(); i++) { + PrintWriter printwriter = PrintWriterRecord.get(i); + printwriter.println("*&pubmsg&*" + "Server:" + str); + printwriter.flush(); + } + } + } catch (IOException e) {} + } + } +} \ No newline at end of file diff --git a/src/com/wecheer/simpleprotx/Spx.java b/src/com/wecheer/simpleprotx/Spx.java new file mode 100644 index 0000000..b4f8ae3 --- /dev/null +++ b/src/com/wecheer/simpleprotx/Spx.java @@ -0,0 +1,40 @@ +package com.wecheer.simpleprotx; + +public interface Spx { + public static final int UID_LENGTH = 10; + public static final int ICON_MAXSIZE = 4096001; + public static final int LAN_DISCOVERY_INTERVAL = 300000; + public static final String WECHEERFILESDIR = "C:\\Users\\WecheerFiles\\"; + + public static final String WECHEER_DATABASE_NAME = "jdbc:mysql://localhost:3306/wcdb"; + public static final String WECHEER_DATABASE_ROOT_NAME = "root"; + public static final String WECHEER_DATABASE_ROOT_KEY = "dqfdxx25"; + + public static final String JDBC_UID_EXISTS = "SELECT UID FROM USERINFO WHERE UID=?;"; + public static final String JDBC_CORRESPONDED_KEY = "SELECT PASSWORD FROM USERINFO WHERE UID=?;"; + public static final String JDBC_WHOAMI = "SELECT UNAME FROM USERINFO WHERE UID=?;"; + public static final String JDBC_WHOARE_MYFRIENDS = "SELECT UID,UNAME FROM USERINFO WHERE UID IN (SELECT UIDA FROM INTIMATE WHERE UIDC=?);"; + public static final String JDBC_INSERT_USERINFO = "INSERT INTO USERINFO (UID,UNAME,PASSWORD) VALUES(?,?,?);"; + + public static final String WHO_AM_I = "whoami?"; + public static final String WHO_ARE_MY_FRIENDS = "whoaremyfriends?"; + public static final String WHO_ARE_ONLINE = "whoareonline?"; + + public static final String PUBLIC_MESSAGE = "*&pubmsg&*"; + public static final String PRIVATE_MESSAGE = "~^@prvt@^~"; + public static final String PRIVATE_PICTURE = "*!#icon#!*"; + public static final String PRIVATE_CONNECTION_REQUEST = "^@privte@^"; + public static final String PRIVATE_CONNECTION_ENQUEST = PRIVATE_CONNECTION_REQUEST; + public static final String PRIVATE_DISCONNECTION_REQUEST = "!^~quit~^!"; + public static final String PRIVATE_DISCONNECTION_ENQUEST = "!#brquit#!"; + public static final String PRIVATE_PARTY_OFFLINE = "^@pvtefl@^"; + public static final String PUBLIC_USERS_ONLINE = "^*&onpu^&*"; + public static final String SIGN_UP = "~^!@su@!~~"; + + public static final String _SEMICOLON = ";"; + public static final String _COMMA = ","; + public static final String _QMARK = "?"; + public static final String _FULLSTOP = "."; + public static final String _COME = "来了"; + public static final String _LEAVE = "走了"; +}