BIO实现:
该程序采用C/S架构
(程序虽然表面上是一个客户端接收其他所有客户端发送过来的消息,其实是每个客户端只对服务器端进行通讯)。
通过IO流进行数据交换。
client:
建立一个socket套接字连接服务器端。
客户端创立两个线程,一个线程负责接收消息,另一个负责发送消息。
server:
每个客户端连上服务端后会在服务端建立一个自定义的管道(MyChannel)<该管道负责拉取和发送消息>
服务端拥有一个储存所有管道的容器。(如list) List<MyChannel> userList = new ArrayList<MyChannel>();
/**
每个管道内各有一个DataInputStream和DataOutputStream,这两个流都是属于服务器
他们分别连接的是客户端的DataOutputStream和DataInputStream
*/
服务器端只需接收到某一个客户端的消息后把这条消息发送给其他客户端(
for(A a : userlist){
if(this==a)
continue;
a.send()
}
)。
Server端:
/** * 每个客户端连上服务端后会在服务端建立一个自定义的管道(MyChannel)<该管道负责拉取和发送消息> * 服务端拥有一个储存所有管道的容器。(如userList) * 每建立一个新的连接后都会把该链接所产生的管道线程扔入userList中 */ public class Server { public static List<MyChannel> userList = new ArrayList<MyChannel>(); public static void main(String[] args) throws Exception{ ServerSocket server = new ServerSocket(9999); System.out.println("------------------Server is Open-----------------"); while (true) { Socket client = server.accept(); MyChannel myChannel = new MyChannel(client); new Thread(myChannel).start(); userList.add(myChannel); } } }
/** * 该类是服务器端的管道的实现类 * 每个管道内各有一个DataInputStream和DataOutputStream,<这两个流都是属于服务器--------记好> * 他们分别连接的是客户端的DataOutputStream和DataInputStream */ public class MyChannel implements Runnable { private DataInputStream dis; private DataOutputStream dos; private boolean isStop = false; public MyChannel(Socket client) { try { dis = new DataInputStream(client.getInputStream()); dos = new DataOutputStream(client.getOutputStream()); } catch (IOException e) { isStop = true; CloseUtil.closeAll(dos,dis,client); } } private String reciveMsg(){ String s = ""; try { s = dis.readUTF(); System.out.println(s); } catch (IOException e) { isStop = true; CloseUtil.closeAll(dis,dos); Server.userList.remove(this); } return s; } private void sendMsg(String s){ if (s != null && !"".equals(s)){ try { dos.writeUTF(s); dos.flush(); } catch (IOException e) { isStop = true; CloseUtil.closeAll(dis,dos); } } } /** * <服务器端只需接收到某一个客户端的消息后把这条消息发送给其他客户端> */ private void sendOther(){ String s = this.reciveMsg(); List<MyChannel> userList = Server.userList; for (MyChannel channel : userList) { if (this == channel) continue; channel.sendMsg(s); } } @Override public void run() { while (!isStop) sendOther(); } }
Client端:
public class Client { private static File file = new File("Client.properties"); private static Properties properties = new Properties(); private static String HOSTNAME = ""; private static int PORT = 0; static { if (!file.exists()){ try { file.createNewFile(); FileOutputStream fos = new FileOutputStream(file); properties.setProperty("hostname","localhost"); properties.setProperty("port","9999"); properties.store(fos,null); fos.close(); } catch (IOException e) { e.printStackTrace(); } } try { properties.load(new FileInputStream(file)); HOSTNAME = properties.getProperty("hostname"); PORT = Integer.parseInt(properties.getProperty("port")); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) throws Exception{ Socket client = new Socket(HOSTNAME,PORT); Scanner input = new Scanner(System.in); System.out.println("客户端已启动,请输入您的昵称:"); String name = input.next(); System.out.println("已进入聊天室!"); new Thread(new SendRun(client),name).start(); new Thread(new ReceiveRun(client),name).start(); } }
ReceiveRun
1 public class SendRun implements Runnable { 2 3 private DataOutputStream dos = null; 4 private boolean isStop = false; 5 private BufferedReader br = null; 6 7 public SendRun(Socket client) { 8 try { 9 br = new BufferedReader(new InputStreamReader(System.in)); 10 dos = new DataOutputStream(client.getOutputStream()); 11 } catch (IOException e) { 12 isStop = true; 13 CloseUtil.closeAll(dos); 14 } 15 } 16 17 private void sendMessage(){ 18 try { 19 dos.writeUTF(Thread.currentThread().getName()+"-->说:"+br.readLine()); 20 dos.flush(); 21 } catch (IOException e) { 22 isStop = true; 23 CloseUtil.closeAll(br,dos); 24 } 25 } 26 27 @Override 28 public void run() { 29 while (!isStop){ 30 this.sendMessage(); 31 } 32 } 33 }
Util类:
1 public class CloseUtil { 2 public static void closeAll(Closeable ... closeables){ 3 for (Closeable clo: closeables) { 4 if (clo!=null) { 5 try { 6 clo.close(); 7 } catch (IOException e) { 8 e.printStackTrace(); 9 } 10 } 11 } 12 } 13 }