Java_聊天室

总述:这个程序是个简化版的聊天室,没有界面,还有待完善,但能实现基本的聊天

Server类,

package socket07;

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

/**
 * 聊天室服务端
 * @author soft01
 *
 */
public class Server07 {
	/*
	 * 运行再服务端的ServerSocket
	 * 有两个主要作用:
	 * 1:向系统申请对外的服务端口,客户端就是通过
	 * 这个端口与服务端建立连接的
	 * 2;监听服务端口,等待客户端连接,一旦一个客户端
	 * 通过Socket与服务端建立连接,那么ServerSocket
	 * 会创建一个Socket与该客户端通讯
	 */
	private ServerSocket server;
	/*
	 * 该数组用于存放所有客户端
	 */
	private PrintWriter[] allOut = new PrintWriter[0]; 
	public Server07() {
		try {
			/*
			 * 创建ServerSocket的同时向系统申请
			 * 对外的服务端口,注意,该端口不能和
			 * 其他程序冲突,否则就会抛出地址被占用
			 * 的异常。
			 */
			server = new ServerSocket(8088);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public void start() {
		try {
			while (true) {
				/*
						 * ServerSocket提供方法:
						 * Socket accept()
						 * 该方法是一个阻塞方法,调用后即等待
						 * 客户端的连接,一旦一个客户端通过
						 * 端口连接,那么accept方法会返回一个
						 * Socket实例,超过这个Socket实例就
						 * 可以与刚连接的客户端交互了
						 */
				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) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public static void main(String[] args) {
		Server07 server = new Server07();
		server.start();
	}
	
	/**
	 * 该线程任务负责与指定Socket所对应的客户端
	 * 进行相互
	 * @author soft01
	 *Handler处理者
	 */
	private class ClientHandler implements Runnable{
		//当前线程通过这个Socket与对应客户端交互
		private Socket socket;
		
		/**
		 * 实例化时将对应客户端的Socket传入
		 * @param socket
		 */
		public ClientHandler(Socket socket) {
			this.socket = socket;
		}
		public void run() {
			PrintWriter pw = null;
			try {
				InputStream in = socket.getInputStream();
				BufferedReader br = new BufferedReader(
						new InputStreamReader(
								in, "UTF-8"
						)
				);
				/*
				 * 获取输出流,用于给当前客户端回复消息
				 */
				pw = new PrintWriter(
						new BufferedWriter(
								new OutputStreamWriter(
										socket.getOutputStream(),
										"UTF-8")
								),true
						);
			synchronized (allOut) {
				//将当前客户端对应的输出流存入共享数组
				//扩容数组
				allOut = Arrays.copyOf(allOut, allOut.length + 1);
				//将输出源存入数组
				allOut[allOut.length - 1] = pw;
			}
				/*
				 * 客户端再断开连接时不同系统有不同反应
				 * linux的客户端断开后,br.readLine方法
				 * 会返回null,
				 * windows的客户端断开连接后,br.readLine方法
				 * 会直接抛出异常 
				 */
				String message = null;
				
				while((message = br.readLine()) != null) {
					System.out.println("客户端说:"+message);
					synchronized (allOut) {
						//回复客户端
						//pw.println("客户端回复说:"+message);
						for (int i = 0; i < allOut.length; i++) {
							allOut[i].println("173服务器说:" + message);
						}
					}
				}
				if(message == null) {
					System.out.println("客户端退出!");
					
				}
			}catch(Exception e) {
				e.printStackTrace();
				
			}finally {
				synchronized (allOut) {
					//处理客户端断开链接后的操作
					//1将该客户端的输出流从共享数组中删除
					for (int i = 0; i < allOut.length; i++) {
						if (allOut[i] == pw) {
							//将最后一个元素放入当前位置
							allOut[i] = allOut[allOut.length - 1];
							//缩容
							allOut = Arrays.copyOf(allOut, allOut.length - 1);
							break;
						}
					}
					/*
					 * 2客户端断开链接后,服务端关闭
					 * 该客户端Socket,释放资源
					 */
				}
				try {
					socket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

Client类

package socket07;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
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 soft01
 *
 */
public class Client07 {
	/*
	 * java.net.Socket
	 * 套接字,封装了TCP协议,Socket提供了两条流
	 * 用来与服务端进行双向通讯
	 */
	private Socket socket;//插座,电话
	public Client07() {
		try {
			//先启动线程接收服务端发送的消息
			
			/*
			 * 实例化Socket就是连接服务端的过程
			 * 参数1:服务端低值
			 * 参数2:服务
			 * 
			 * 通过服务器IP地址可以找到服务端所处
			 * 计算机,再通过端口找到运行在服务端
			 * 计算机上的服务端应用程序。
			 */
			//localhost
			
			//192.168.28.157
			//192.168.28.233 42
			//192.168.28.173 44
			//192.168.28.237 43
			socket = new Socket("localhost", 8088);//相当于连接成功
		}catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	/**
	 * 客户端 开始工作的方法
	 */
	public void start() {
		
		try {
			ServerHandler handler = new ServerHandler();
			Thread t = new Thread(handler);
			t.start();
			/*
			 * Socket提供方法:
			 * OutputStream getOutputStream()
			 * 通过返回的子字节输出流写出的数据会发送
			 * 给远端计算机,对于客户端这边而言远端
			 * 计算机就是服务端了
			 */
			OutputStream out = socket.getOutputStream();
			PrintWriter pw = new PrintWriter(
					new BufferedWriter(
							new OutputStreamWriter(
									out,"UTF-8"
									)
							),true
					); 
			
			
			while (true) {
				Scanner scanner = new Scanner(System.in);
				System.out.println("请输入您要输入的信息");
				String line = scanner.nextLine();
				if("exit".equals(line)) {
					System.out.println("退出!");
					break;
				}
				pw.println(line);

			}
		} catch (IOException e) {

			e.printStackTrace();
		}
		
	}
	public static void main(String[] args) {
		Client07 client = new Client07();
		client.start();
	}
	/**
	 * 该线程负责循环接收服务端发送过来的消息
	 * 给服务端发送消息与接收服务端发过来的消息
	 * 要放在两个不同的线程里运行,这样才能做到
	 * 互相不干扰
	 * @author soft01
	 *
	 */
	private class ServerHandler implements Runnable{
		
		public void run() {

			try {
				BufferedReader br = new BufferedReader(
						new InputStreamReader(
								socket.getInputStream(),"UTF-8"
						)
				);
				String message = null;
				while((message = br.readLine()) != null) {
					System.out.println("173说:"+message);
				}
			} catch (IOException e) {
				
			}
			
		}
		
	}
}

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页