当前的服务器只有向客户端发送数据的功能,并没有从客户端读取数据的功能,所以只能实现单对单的通信(不能实现相互通信)。
因此,有必要创建一个chatmanager类,把进程管理起来,实现相互通信。
一、代码实现
因为一个聊天服务器只能有一个管理的manager,所以要对manager类做单例化处理。
简单的单例化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package testmyserversocket; public class chatmanager { private chatmanager() { } private static final chatmanager cm = new chatmanager(); public static chatmanager getchatmanager() { return cm; } } |
实际上这种实现单例的方法不安全,会引起一些问题。对于实现安全的单例化,可以参考后面的文章。
完整的代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
package testmyserversocket; import java.util.Vector; public class chatmanager { private chatmanager() { } private static final chatmanager cm = new chatmanager(); public static chatmanager getchatmanager() { return cm; } Vector<chatsocket> vector = new Vector<chatsocket>();// 结合,线程的集合 public void add(chatsocket cs)// 为当前集合添加websocket这样一个对象 { vector.add(cs); } public void publish(chatsocket cs, String out/* 有一个线程想调用这个函数的话,首先要把自己传进来 */)// 其中的每一个线程可以通过调用这个函数向其他客户端发送信息 { // 然后需要传入当前的需要发送的信息out // 因为要发送给集合中所有的线程,所以需要便利,使用for循环 for (int i = 0; i < vector.size(); i++) { chatsocket chatsocket = vector.get(i);// 创建一个本地的对象,获取循环中的第i个对象 if (!cs.equals(chatsocket)) // 需要进行一个判断,因为当前发送这条信息的线程不需要再接受这条信息了 { // 如果发送对象是当前对象,就不发送 // 所以用!进行反转,不是当前对象则发送消息 chatsocket.out(out);// 用out方法把字符串传递走出去 } } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
package testmyserversocket; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.net.Socket; public class chatsocket extends Thread { Socket socket; public chatsocket(Socket s) { this.socket = s; } public void out(String out) { try { socket.getOutputStream().write(out.getBytes("UTF-8")); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public void run() { // 在run方法中要进行接受数据的工作 // run方法中,循环执行的是读取的工作,当前服务器会不断地从客户端中读取内容 // 将读取的内容发送到vector集合中的所有的客户端中 try { BufferedReader br = new BufferedReader( new InputStreamReader( socket.getInputStream(),"UTF-8")); String line = null; while((line = br.readLine()) != null)//客户端发送给服务器的数据不为空时 { //就把这条数据发送给聊天室里的所有人,需要调用publish方法 chatmanager.getchatmanager().publish(this, line); } br.close();//while循环结束时需要把流关闭 } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
package testmyserversocket; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import javax.swing.JOptionPane; public class serverlistener extends Thread { @Override public void run() { // 端口号1-65535 int port = 12345; try { ServerSocket ss = new ServerSocket(port); while (true) { // accept会阻塞当前main线程,block Socket sk = ss.accept(); // 建立连接 JOptionPane.showConfirmDialog(null, "有客户端连接到了本机的12345端口"); chatsocket cs = new chatsocket(sk); cs.start(); chatmanager.getchatmanager().add(cs); } } catch (IOException e) { e.printStackTrace(); } } } |
1 2 3 4 5 6 7 8 |
package testmyserversocket; public class myserversocket { public static void main(String[] args) { new serverlistener().start(); } } |
二、总结
通过以上的简单代码,可以实现不同客户端间的通信。