• 基于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();
    	}
    	
    }  
  • 相关阅读:
    NOIP 2011 DAY 2
    NOIP 2011 DAY 1
    扩展欧几里得算法(exgcd)
    中国剩余定理
    线性同余方程的求解
    乘法逆元
    poj 1845 Sumdiv(约数和,乘法逆元)
    欧拉-费马小定理定理(证明及推论)
    求解范围中 gcd(a,b)== prime 的有序对数
    KindEditor解决上传视频不能在手机端显示的问题
  • 原文地址:https://www.cnblogs.com/lizhangyong/p/8610044.html
Copyright © 2020-2023  润新知