我之前写过一篇博客,主要是基于TCP协议实现的聊天室swing版,在此再写一个基于TCP协议实现的聊天室控制台版,便于学习和比较。
package 聊天室console版.utils; import java.net.InetAddress; import java.net.UnknownHostException; /** * 工具类,服务器端的有关信息 * @author 李章勇 * */ public abstract class HostInfo { //访问权限,供不同包访问 public static String ip=getIp(); public static final int port=10086; public static final int num=50; private static String getIp(){ try { return InetAddress.getLocalHost().getHostAddress(); } catch (UnknownHostException e) { e.printStackTrace(); return null; } } } ------------------------------------------------------- package 聊天室console版.utils; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; /** * 工具类,释放资源 * @author 李章勇 * */ public abstract class Release { //访问权限,public,可以供不同包的对象访问 public static void release(Socket socket,BufferedWriter bw){ release(null,socket,null,bw); } public static void release(Socket socket,BufferedReader br){ release(null,socket,br,null); } public static void release(Socket socket){ release(null,socket,null,null); } public static void release(ServerSocket server){ release(server,null,null,null); } public static void release(ServerSocket server,Socket socket,BufferedReader br,BufferedWriter bw){ if(server!=null){ try { server.close(); } catch (IOException e) { System.err.println("服务器创建失败!"); } } if(socket!=null){ try { socket.close(); } catch (IOException e) { System.err.println("客户端创建失败!"); } } if(br!=null){ try { br.close(); } catch (IOException e) { System.err.println("输入流创建失败!"); } } if(bw!=null){ try { bw.close(); } catch (IOException e) { System.err.println("输出流创建失败!"); } } } } -------------------------------------------------------------------- package 聊天室console版.server; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.List; import 聊天室console版.utils.HostInfo; import 聊天室console版.utils.Release; /** * 服务器端类 * 要先开启服务器,再开启客户端 * @author 李章勇 * */ public class Server { //仅可以在同一包内访问 涉及查询和增删 用ArrayList集合 static List<Transport> clients=new ArrayList<>(); //服务器构造器 public Server(){ //创建服务器套接字,工具类中的属性 ServerSocket server=null; try { server=new ServerSocket(HostInfo.port); } catch (IOException e) { Release.release(server); throw new RuntimeException("服务器端口被占!启动服务器失败!"); } System.out.println("服务器开启成功!"); //接收来自客户端的连接请求,最多接收50个 int num=0; Socket socket=null; while(num<HostInfo.num){ try { socket=server.accept(); } catch (IOException e) { //释放资源,结束本次循环,进行下一轮循环 Release.release(socket); continue; } System.out.println("第 "+(++num)+" 个客户端成功接入!==" +socket.getInetAddress().getHostAddress() +":"+socket.getPort()); //另起一个子线程,专门处理与客户端的数据交互,同时传递入该socket对象 Transport //并将该转发类对象存入一个集合对象 clients.add(new Transport(socket)); } System.err.println("超出服务器负荷!"); Release.release(server); } //服务器主线程 public static void main(String[] args) { new Server(); } } ------------------------------------------------- package 聊天室console版.server; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.Socket; import 聊天室console版.utils.Release; /** * 服务器端,处理信息(客户端发来的,以及给客户端转发的) * @author 李章勇 * */ public class Transport extends Thread { //访问权限 仅供本类对象使用 private Socket socket; private String ip; public Transport(Socket socket){ this.socket=socket; this.ip=socket.getInetAddress().getHostAddress(); this.start(); } @Override public void run() { //从客户端获取流 BufferedReader br=null; BufferedWriter ownbw=null; try { br=new BufferedReader(new InputStreamReader(socket.getInputStream())); ownbw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); } catch (IOException e) { Server.clients.remove(this); Release.release(socket, br); throw new RuntimeException("获取流失败!"); } //从客户端流中循环读数据 String str=null; try { while((str=br.readLine())!=null){ String[] split = str.split(":", 2); if(split.length<=1){ ownbw.write("您发送的数据格式有误,请重新发送!"); ownbw.newLine(); ownbw.flush(); }else{ String desip=split[0]; String content=split[1]; //判断对方是否在线,准备给给目标转发信息 BufferedWriter desbw=null; boolean isOnLine=false; for(Transport des:Server.clients){ if(desip.equals(des.ip)){ isOnLine=true; desbw=new BufferedWriter(new OutputStreamWriter(des.socket.getOutputStream())); desbw.write(ip+" -->对你说:"+content); desbw.newLine(); desbw.flush(); } } if(!isOnLine){ ownbw.write("对方 "+desip+"不在线!"); ownbw.newLine(); ownbw.flush(); } } } } catch (IOException e) { Server.clients.remove(this); Release.release(socket, br); throw new RuntimeException("获取流失败!"); } } } ----------------------------------------------------------- package 聊天室console版.client; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.Socket; import java.net.UnknownHostException; import java.util.Scanner; import 聊天室console版.utils.HostInfo; import 聊天室console版.utils.Release; /** * 客户端类 * @author 李章勇 * */ public class Client { private Socket socket=null; public Client(){ //向服务器发起连接请求 try { socket=new Socket(HostInfo.ip, HostInfo.port); }catch (IOException e) { Release.release(socket); throw new RuntimeException("客户端创建失败!"); } //另建一个子线程从服务器循环读取数据 new Receive().start(); //向服务器循环写流 BufferedWriter bw=null; Scanner sc=new Scanner(System.in); String str=null; try { bw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); while(true){ System.out.println("请发送数据(格式-->对方ip:信息内容):"); str=sc.nextLine(); bw.write(str); bw.newLine(); bw.flush(); } } catch (IOException e) { Release.release(socket, bw); throw new RuntimeException("向服务器写流失败!"); } } private class Receive extends Thread{ @Override public void run() { BufferedReader br=null; try { br=new BufferedReader(new InputStreamReader(socket.getInputStream())); } catch (IOException e) { Release.release(socket, br); throw new RuntimeException("从服务器获取流失败!"); } String str=null; //从服务器循环获取流 try { while((str=br.readLine()) != null){ System.out.println(str); } } catch (IOException e) { Release.release(socket, br); throw new RuntimeException("从服务器获取流失败!"); } } } public static void main(String[] args) { new Client(); } }