1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 聊天室案例 模仿QQ 微信群聊

聊天室案例 模仿QQ 微信群聊

时间:2018-12-26 06:42:01

相关推荐

聊天室案例 模仿QQ 微信群聊

使用说明

这个代码是模拟一个简单的QQ,微信群聊,首先运行服务端代码,在运行客户端,每运行一次客户端,都会创建一个用户在聊天室中模拟发言。(注:服务端要一直处于开启状态,不能关闭)

客户端代码

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.io.UnsupportedEncodingException;import .Socket;import .UnknownHostException;import java.util.Scanner;public class Client {/** 在整个客户端类中都会使用到Socket对象,所以生命成属性。* Socket内部封装了TCP协议,可以完成安全可靠的数据传输。* * 客户端向服务端发送数据时,需要使用输出流进行操作。*/private Socket socket;/*** 客户端无参构造器* 目的:用于创建客户端对象时,对socket属性进行初始化* */public Client() {try {System.out.println("开始连接");/** Socket实质是用于描述IP地址和端口号* 当创建Socket对象时需要调用两个参数的构造器方法* 参数一:需要指定IP(服务端的IP地址)* 参数二:需要指定端口号(服务端的端口号)*/socket = new Socket("localhost", 8899);System.out.println("连接服务端成功");} catch (UnknownHostException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}}/*** 向服务端写出数据的方法*/public void start() {/** 如果需要发送消息,要使用socket对象获取输出流* getOutputStream()方法的返回值要求返回一个OutputStream*/try {//创建接受服务端的消息线程,并添加任务序列ServerHandler serverHandler = new ServerHandler();Thread thread = new Thread(serverHandler);thread.start();OutputStream os = socket.getOutputStream();//创建字符转换流对象OutputStreamWriter osw = new OutputStreamWriter(os, "utf-8");//创建缓冲字符输出流对象BufferedWriter bw = new BufferedWriter(osw);//创建具备自动行数新功能的字符输出流PrintWriter pw = new PrintWriter(bw, true);//通过控制台接受客户端消息Scanner scanner = new Scanner(System.in);while (true) {String message = scanner.nextLine();pw.println(message);}} catch (IOException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}}public static void main(String[] args) {//创建客户端对象Client client = new Client();client.start();}/*** 用于处理服务端发送过来的数据的读取操作*/class ServerHandler implements Runnable {@Overridepublic void run() {try {InputStream is = socket.getInputStream();//创建字符转换流对象InputStreamReader isr = new InputStreamReader(is,"utf-8");//创建缓冲字符输入流对象BufferedReader br = new BufferedReader(isr);//读取数据,按行进行读取String message;while ((message = br.readLine()) != null) {System.err.println(message);}} catch (Exception e) {e.printStackTrace();}}}}

服务端代码

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 .ServerSocket;import .Socket;import java.util.Arrays;public class Server {/** 声明服务端ServerSocket对象*/private ServerSocket serverSocket;/** 定义一个输出流数组,保存的是指向各个客户端的输出流对象*/private PrintWriter[] allout = {};/*** 服务端无参构造器* 目的:用于创建服务端对象时,对serverSocket属性进行初始化* */public Server() {try {System.out.println("服务端正在启动");serverSocket = new ServerSocket(8899);System.out.println("服务端启动完毕");} catch (IOException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}}/*** 服务端接收客户端消息的方法*/public void start() {/** Socket accept()方法是一个阻塞方法,* 循环等待客户端连接,如果没有客户端连接就一直在这等着。*/try {while (true) {System.out.println("等待接收客户端连接");Socket socket = serverSocket.accept();System.out.println("一个客户端已经连接");/** 创建任务序列对象* 创建线程对象并添加任务序列* 开启线程* 目的:等待客户端连接以后,可以开启一条线程,* 在新的线程中用于处理客户端连接后的一些列操作*/ClientHandler clientHandler = new ClientHandler(socket);Thread thread = new Thread(clientHandler);thread.start();}} catch (IOException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}}public static void main(String[] args) {//创建服务端对象Server server = new Server();server.start();}/*** 用于处理客户端请求的内部类,* 主要的职责是充当线程的任务序列,* 在任务序列中,主要做获取输入流对象,循环判断,* 及其信息输出的操作。* @author Administrator**/class ClientHandler implements Runnable{//客户端发送过来的Socket对象Socket socket;//客户端的地址信息String host;public ClientHandler(Socket socket) {this.socket = socket;this.host = socket.getInetAddress().getHostAddress();}@Overridepublic void run() {//字符输出流局部变量PrintWriter pw = null;try {/** 如果需要从服务端打印客户端传输的信息,* 需要从Socket中获取输入流*/InputStream is = socket.getInputStream();//创建字符转换流对象InputStreamReader isr = new InputStreamReader(is,"utf-8");//创建缓冲字符输入流对象BufferedReader br = new BufferedReader(isr);/** 获取Socket中的输出流对象,用于给客户端写出数据*/OutputStream os = socket.getOutputStream();OutputStreamWriter osw = new OutputStreamWriter(os,"utf-8");BufferedWriter bw = new BufferedWriter(osw);pw = new PrintWriter(bw,true);//将输出流对象添加到allout输出流数组中synchronized (allout) {//对原数进行扩容allout = Arrays.copyOf(allout, allout.length+1);//对数组中的最后一个元素进行赋值allout[allout.length-1] = pw;}//在控制台中打印当前在线人数System.out.println(host+"上线了,当前在线人数为:"+allout.length);//读取数据,按行进行读取String message;while ((message = br.readLine()) != null) {System.err.println(host+"说:"+message);//读取消息以后就向客户端写出synchronized (allout) {//遍历输出流数组,向所有的客户端输出数据for (int i = 0; i < allout.length; i++) {allout[i].println(host+"说了:"+message);}}}} catch (Exception e) {/** 如果停掉客户端会发生异常,可以在当前的catch块中* 进行处理删除发送给当前已经停止掉的客户端的输出流对象*/synchronized (allout) {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;}}}} finally {System.out.println(host+"下线了,当前在线人数:"+allout.length);try {//关闭Socket资源socket.close();} catch (IOException e) {}}}}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。