这有点爽的
简单应用了一下多线程,搞定了多客户端的问题。
之前只能有一个客户端接入,因为服务器只会accept()一次,然后就进入接收输入流的死循环了。
然后我趴在地上想了一下,主进程里死循环来accept(),然后每个客户端new一个新进程是不是就搞定了,越想越觉得有道理,于是就试了试。
另外每个进程里重新各new一个Socket和输入流,这样就不会跟主进程产生冲突,同时主进程里的这两个也就可以直接删掉了。
于是现在是各个进程各自处理自己的接收信息动作,互不干涉。
启动进程是start()不是run()哪。
现在的问题是服务器已经把该接收的都接收了,怎么把客户端发上来的消息再发给其他客户端呢。
不可能在服务器里放一个StringBuffer,虽然这样很稳妥,也能解决问题,但是这样消耗带宽越来越大……
另一种方法是客户端发上来消息之后先不更新自己的文本框内容,由服务器向所有客户端来发送,也就是说我发一条消息要发上去再下下来,是不是有点蛋疼,虽然这样也可以解决问题。
诸君,我从小学开始就最擅长找笨办法了……
智商低好痛苦 _(:з」∠)_
1 import java.io.*; 2 import java.net.*; 3 4 /** 5 * 服务器端,目前还是单纯的解包并在命令行打印,再下个版本改。 6 * 1. 处理了端口已占用的异常。 7 * 2. 客户端退出后不关闭进程。 8 * 3. *重要内容* 改用多进程的方式,支持了多客户端接入。 9 * 不过目前只能接收信息命令行打印。 10 * 之后加上向其他客户端发送消息的功能。 11 * 12 * @author mlxy 13 * @version 0.6 14 * */ 15 public class SimChatServer { 16 ServerSocket ss = null; 17 int users; 18 19 /** 服务器构造方法,只用来初始化已连接客户端数。*/ 20 public SimChatServer() {users = 0;} 21 22 public static void main(String[] args) { 23 SimChatServer server = new SimChatServer(); 24 25 // 尝试启动服务器,端口被占用则提示并退出。 26 try { 27 server.ss = new ServerSocket(2333); 28 } catch (BindException e) { 29 System.out.println("Port occupied."); 30 System.exit(0); 31 } catch (IOException ex) { 32 ex.printStackTrace(); 33 } 34 35 // 死循环,等待客户端连接,连接成功则启动一个新线程。 36 try { 37 do { 38 server.new ClientThread(server, server.ss.accept()).start(); 39 server.users++; 40 System.out.println("Current clients: " + server.users); 41 } while (server.users > 0); 42 43 } catch (IOException e) { 44 e.printStackTrace(); 45 } 46 47 48 } 49 50 /** 管理客户端退出的方法。*/ 51 private void clientOut() { 52 users--; 53 System.out.println("Current clients: " + users); 54 55 // 所有客户端都断开之后关闭服务器。 56 if (users == 0) { 57 System.out.println("All clients are out, server abort."); 58 try { 59 ss.close(); 60 } catch (IOException e) { 61 e.printStackTrace(); 62 } 63 } 64 } 65 66 /** 67 * 内部类。 68 * 单个客户端线程,包含了处理客户端发来信息的方法。 69 * 目前只能接收信息,之后再加上向客户端发包的功能。 70 * 71 * @author mlxy 72 * @version 0.5 73 */ 74 class ClientThread extends Thread { 75 SimChatServer server; 76 Socket singleSocket; 77 ObjectInputStream singleInput; 78 79 /** 一个客户端线程的构造方法。*/ 80 public ClientThread(SimChatServer server, Socket singleSocket) { 81 this.server = server; 82 this.singleSocket = singleSocket; 83 System.out.println("Client connected."); 84 try { 85 singleInput = new ObjectInputStream(singleSocket.getInputStream()); 86 } catch (IOException e) { 87 e.printStackTrace(); 88 } 89 } 90 91 @Override 92 public void run() { 93 // 主运行部分,抓到客户端退出的异常就打印提示并退出。 94 try { 95 // 死循环,读包拆包打印。 96 while (true) { 97 String[] packReceived = (String[]) singleInput.readObject(); 98 System.out.println(packReceived[0] + ": " + packReceived[1]); 99 } 100 101 } catch (ClassNotFoundException e) { 102 e.printStackTrace(); 103 } catch (EOFException ex) { 104 System.out.println("Client disconnected."); 105 } catch (IOException exc) { 106 exc.printStackTrace(); 107 } finally { 108 // 关闭所有引用,释放资源。 109 try { 110 if (singleSocket != null) 111 singleSocket.close(); 112 if (singleInput != null) 113 singleInput.close(); 114 115 // 报告一个客户端退出。 116 server.clientOut(); 117 } catch (IOException e) { 118 e.printStackTrace(); 119 } 120 } 121 } 122 123 } 124 }