基于TCP协议的聊天室控制台版

  我之前写过一篇博客,主要是基于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();
	}
	
}  
原文地址:https://www.cnblogs.com/lizhangyong/p/8610044.html