客户端:
多个客户可以正常收发信息,因为可以同时发送和接受信息,不是发送完信息后等待
返回信息,所以要加入多线程

public class Client {public static void main(String[]args) throws UnknownHostException, IOException{ System.out.println("客户端启动中..."); BufferedReader br =new BufferedReader(new InputStreamReader(System.in)); System.out.println("请输入用户名:"); String name=br.readLine(); Socket client =new Socket("localhost",9999); new Thread(new Send(client,name)).start();//在线程还没启动之前,通过构造方法发送名称,先于信息的发送, //因为接收信息时,名称已经发送并被读取到变量中 new Thread(new Receive(client)).start();}}

作为释放资源工具类

public class utils {public static void close(Closeable... target ){ for(Closeable it:target) { try { if(null!=it) { it.close(); } } catch (IOException e) { e.printStackTrace(); } } }}

客户端的发送端封装了:
发送消息
从键盘读取消息
run()
释放资源

public class Send implements Runnable{private BufferedReader br;private DataOutputStream dos;private Socket client;private boolean flag=true;private String name;public Send(Socket client,String name){ this.client=client; this.name=name; br=new BufferedReader(new InputStreamReader(System.in)); try { dos=new DataOutputStream(client.getOutputStream()); //发送名称 send(name); } catch (IOException e) { this.release(); }}public void run(){ while(flag) { String msg=getstr(); send(msg); }}private void release(){ this.flag=false; utils.close(dos,client);}//从控制台获取消息private String getstr(){ try { String msg=br.readLine(); return msg; } catch (IOException e) { e.printStackTrace(); } return null;}private void send(String msg){ try { dos.writeUTF(msg); dos.flush(); } catch (IOException e) { release(); }}}

客户端的接收端封装了:
接收消息
run()
释放资源

public class Receive implements Runnable {private DataInputStream dis;private Socket client;private boolean flag=true;public Receive(Socket client){ this.client=client; try { dis=new DataInputStream(client.getInputStream()); } catch (IOException e) { release(); }}private String receive(){ String msg; try { msg = dis.readUTF(); return msg; } catch (IOException e) { release(); } return null;}public void run(){ while(flag) { String msg=receive(); System.out.println(msg); }}private void release(){ this.flag=false; utils.close(dis,client);}}

在线聊天室
服务器:

public class Chat {private static CopyOnWriteArrayList<channel> list=new CopyOnWriteArrayList<>();//使用并发容器,适合多线程public static void main(String[]args) throws IOException{ System.out.println("服务器启动中..."); ServerSocket server=new ServerSocket(9999); while(true) { Socket client =server.accept(); System.out.println("一个客户端建立了连接"); channel c=new channel(client); list.add(c); //容器管理所有成员 new Thread(c).start(); }}static class channel implements Runnable{ private DataInputStream dis; private DataOutputStream dos; private BufferedReader br; private Socket client; private boolean flag; private String name; public channel(Socket client) { this.client=client; try { dis=new DataInputStream(client.getInputStream()); dos=new DataOutputStream(client.getOutputStream()); flag=true; //获取名称 this.name=receive(); //欢迎到来 this.send("欢迎来到聊天室"); this.sendothers(this.name+"来到了聊天室",true); } catch (IOException e) { release(); } } //接收消息 private String receive() { try { String msg=dis.readUTF(); return msg; } catch (IOException e) { release(); } return null; } //发送给消息 private void send(String msg) { try { dos.writeUTF(msg); dos.flush(); } catch (IOException e) { release(); } } //群聊:获取自己的消息,发给其他人和私聊功能 private void sendothers(String msg,boolean issys) { boolean issecrete =msg.startsWith("@"); if(issecrete) { int index=msg.indexOf(":"); String target=msg.substring(1,index); msg=msg.substring(index+1); for(channel it:list) { if(it.name.equals(target)) //查找目标 { it.send(this.name+"悄悄地对你说:"+msg); //私聊消息 break; } } }else { for(channel it:list) { if(it==this) { continue; } if(!issys) { it.send(this.name+":"+msg); }else { it.send(msg); } } } } private void release() { this.flag=false; utils.close(dis,dos,client); //写一个工具类,使用Closeable...可变参数 //退出时,从容器里面移掉自身 list.remove(this); sendothers("离开了聊天室",false); } public void run() { while(flag) { String msg=receive(); sendothers(msg,false); } release(); }}}