Java 聊天室,可多人聊天,无UI界面

简易聊天室,顾名思义,就是简易到不能再简易,没有用到JFrame窗口化,直接在console调试。
其中用到的io流和API有:
缓冲流:BufferedReader和BufferedWriter
作用:缓冲流是一对高级流,作用是提高读写的效率,缓冲流内部有一个缓冲区(byte数组,默认长度8K)
无论是单字节读写还是缓冲流读写,都以块读写进行。
字节流:InputStream和OutputSream
java把 IO 定义了两个超类:InputStream输入流和OutputSream输出流
转换流:InputStreamReader和OutputStreamWriter
作用:实现字节流和字符流之间的转换,这两个流属于字符流
打印流:PrintWriter
只操作目的地,不操作数据源,可以操作任意类型的数据,如果启用了自动刷新,在调用println()方法的时候加true,能够自动换行并刷新
socket网络编程
在网络编程中,网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket
Scanner就不用说了

package socket1;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

/**
 * 聊天室客户端
 * @author pc
 */
public class Client {
	/*
	 * java.net.Socket 套接字
	 * Socket封装了TCP协议的通讯细节,使用它可以与远端
	 * 计算机建立连接,并使用两个流的读写完成与远端计算机
	 * 的数据交换。
	 */
	private Socket socket;
	public Client() {
		try {
			/*
			 * Socket常用构造器:
			 * Socket(String host,int port)
			 * host:远端计算机的地址(IP)
			 * port:远端计算机打开的端口
			 * 调用该构造器实例化Socket的过程就是与远端
			 * 计算机建立连接的过程。如果连接失败会抛出
			 * 异常。
			 * 通常与远端计算机进行连接时我们通过IP地址找
			 * 到网络上要连接的计算机,通过端口与运行在该
			 * 计算机上的服务端应用程序建立连接。
			 */
			System.out.println("正在连接服务端...");
			/**
			 * localhost表示本机地址
			 * 
			 * 查询本机的IP地址:
			 * windows:
			 * 点击桌面左下角的windows图标,然后输入
			 * cmd回车。在弹出的控制台中输入:ipconfig
			 * 
			 * linux:
			 * 在桌面鼠标右键,选择打开终端程序。
			 * 然后输入:/sbin/ifconfig
			 * 
			 */
			socket = new Socket("localhost",8088);
			System.out.println("与服务端建立连接!");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void start() {
		try {
			//首先读取服务端发送过来的消息的线程启动
			ServerHandler handler = new ServerHandler();
			Thread t = new Thread(handler);
			t.start();
			/*
			 * Socket提供的方法:
			 * OutputStream getOutputStream()
			 * 返回一个字节输出流,通过这个流写出的字节会
			 * 发送给远端计算机	 
			 */
			OutputStream out = socket.getOutputStream();//字节输出流
			OutputStreamWriter osw = new OutputStreamWriter(out);//转换流,字符转换字节		
			BufferedWriter bw = new BufferedWriter(osw);//块读写,加速流,可按行读写
			PrintWriter pw = new PrintWriter(bw,true);//缓冲字符输出流
			
//			//通过socket获取输入流,读取服务端发送过来的消息
//			InputStream in = socket.getInputStream();//字节输入流
//			InputStreamReader isw = new InputStreamReader(in);//转换流,字节转换字符
//			BufferedReader br = new BufferedReader(isw);//缓冲字符输入流,加速读写
//			
			Scanner scanner = new Scanner(System.in);
			while(true) {
				String line = scanner.nextLine();
				pw.println(line);//写出
				
//				line = br.readLine();//读取
//				System.out.println(line);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	public static void main(String[] args) {
		Client client = new Client();
		client.start();
	}
	private class ServerHandler implements Runnable{
		@Override
		public void run() {
			/*
			 * Socket提供的方法:
			 * InputStream getInputStream()
			 * 获取一个字节输入流,通过它可以读取远端计算机
			 * 发送过来的字节
			 */
			try {
				InputStream in = socket.getInputStream();//字节输入流
				InputStreamReader isr = new InputStreamReader(in);//转换流,字节转换字符		
				BufferedReader br = new BufferedReader(isr);//缓冲字符输入流,加速读写
				
				//循环读取服务端发送过来的每一行消息
				String message;
				while((message = br.readLine())!=null) {//读取
					System.out.println(message);
				}
			} catch (IOException e) {
				e.printStackTrace();
			}finally {
				try {
					//当调用socket的close方法后,通过它获取的输入流与输出流就自动关闭了
					socket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}
package socket1;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;

/**
 * 聊天室服务端
 * @author pc
 *
 */
public class Server {
	/*
	 * java.net.ServerSocket
	 * ServerSocket是运行在服务端的,它主要有两个作用:
	 * 1:申请并打开服务端口,客户端就是通过这个端口与
	 *   服务端建立连接的
	 * 2:监听该端口,一旦一个客户端连接后会自动创建Socket
	 *   实例,通过这个Socket便可以与刚连接上的客户端进行
	 *   交互
	 */
	private ServerSocket server;
	private PrintWriter[] allOut = {};
	public Server() {
		try {
			System.out.println("正在启动服务端...");
			/*
			 * 如果申请的端口已经被其他程序占用时,这里
			 * 的实例化会抛出异常:
			 * java.net.BindException: address already in use
			 */
			server = new ServerSocket(8088);
			System.out.println("启动服务端完毕!");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	public void start() {
		try {
			/*
			 * ServerSocket提供的方法:
			 * Socket accept()
			 * 该方法是一个阻塞方法,调用后程序"卡住",
			 * 直到一个客户端建立连接,此时accept方法
			 * 会立即返回一个Socket实例,通过这个Socket
			 * 与客户端进行交互。
			 */
			while(true) {
				System.out.println("等待客户端连接...");
				Socket socket = server.accept();
				System.out.println("一个客户端连接了!");
				//启动一个线程处理该客户端交互
				ClientHandler handler = new ClientHandler(socket);
				Thread t = new Thread(handler);
				t.start();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	public static void main(String[] args) {
		Server server = new Server();
		server.start();
	}
	/**
	 * 该线程任务是负责与指定客户端交互的
	 * @author pc
	 */
	private class ClientHandler implements Runnable{
		private Socket socket;
		private String host;
		public ClientHandler(Socket socket) {
			this.socket = socket;
			host = socket.getInetAddress().getHostAddress();
		} 
		public void run() {
			try {
				/*
				 * Socket提供的方法:
				 * InputStream getInputStream()
				 * 获取一个字节输入流,通过它可以读取远端计算机
				 * 发送过来的字节
				 */
				InputStream in = socket.getInputStream();//字节输入流
				InputStreamReader isr = new InputStreamReader(in);//转换流,字节转换字符		
				BufferedReader br = new BufferedReader(isr);//缓冲字符输入流,加速读写
				//通过socket获取输出流以便给当前客户端发送信息
				OutputStream os = socket.getOutputStream();//字节输出流
				OutputStreamWriter osw = new OutputStreamWriter(os);//转换流,字符转换字节	
				BufferedWriter bw = new BufferedWriter(osw);//块读写,加速流,可按行读写
				PrintWriter pw = new PrintWriter(bw,true);//缓冲字符输出流
				//将当前客户端的输出流存入allOut中
				//1:对allOut数组扩容
				allOut = Arrays.copyOf(allOut, allOut.length+1);
				//2:将输出流存入数组最后一个位置
				allOut[allOut.length-1] = pw;
				System.out.println(host+"上线了!当前在线人数:"+allOut.length);
				
				String message;
				while((message = br.readLine())!=null) {//读取
					System.out.println(host+"客户端说:"+message);
					//将消息发送给所有客户端
					for (int i = 0; i < allOut.length; i++) {
						allOut[i].println(host+"说:"+message);
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值