创建专属聊天室练习(客户端与服务端通信|客户端界面交互)
一、知识回顾与补充
package frame;import javax.swing.*;//只是发现以后所有的框都是按照刚才那套流程画出来的
//只不过具体的组件,位置,布局都不一样,但是需要做的事情抽象来看都是一样的
//设计一个抽象的规则//模板方法模式 23个设计模式当中的一个//还有一种是:缺省适配器模式 MyFrame(接口 10个) baseFrame(挑一些不重要的实现掉{} 子类去实现一些必要的方法)
public abstract class BaseFrame extends JFrame {public BaseFrame(String title){super(title);}protected abstract void setOther();protected abstract void addElements();protected abstract void setSelf();
}
package frame;import javax.swing.*;
import java.awt.*;//简单梳理一下关于Swing的技术
//GUI 图形用户接口(规则) Client/Server
//GUI下面有两个接口:AWT Swing。 可以做但很少用来基于Browser/Server HTML <html></html>
//想要利用Swing技术来实现一个窗口的绘制
//里面有JFrame窗体 可看成类似于<body>
//还有JPanel面板 可看成类似于<div><span> 无色透明的容器 做布局管理
//各种组件 按钮 文本框 文本域 理解为HTMl中那些<input type="button">
//JButton按钮 JTextField
//最终肯定是需要有功能 事件-方法 HTML(布局)+CSS(样式)+JS(事件) Tomcat
//事件背后才是我们真正需要实现的强大逻辑/功能//============================================================
//需要自己描述一个类
//可能需要描述属性,方法
//类与类的关系
//继承 泛化(实现) A is a B
// 聚合 组合 A has-a B
// 包含 依赖 A use-a B
public class QQFrame extends BaseFrame{//是一个窗口 类和类之间的关系 A is-a B 继承//1.需要一个窗体/窗口private JFrame frame=new JFrame("聊天框");//GC 边界管理//2.需要一个无色透明的容器--面板private JPanel panel=new JPanel();// 流式管理 可以有多个//3.需要一些聊天窗口的组件//这是两个带滚动条的文本域private JTextArea messArea=new JTextArea();private JScrollPane messPane=new JScrollPane(messArea);//滚动条范围大,里面是包着文本域的private JTextArea sendArea=new JTextArea();private JScrollPane sendPand=new JScrollPane(sendArea);//两个按钮private JButton sendButton=new JButton("发送");private JButton cancelButton=new JButton("取消");//构造方法 里面可以放这三个方法,或者这三个方法可以放在代码块,让它在构造方法之前加载public QQFrame(String title){super(title);//2.调用里面的方法this.setOther();this.addElements();this.setSelf();}//设计一个方法 做一些设置 布局 字体。。@Overrideprotected void setOther(){//4.为了让布局更好的好看一点,我们采用一个自动布局的方式// 自定义布局需要将原有的布局清空panel.setLayout(null);//所有的组件按照自己的设计位置放置messPane.setBounds(10, 10, 320, 220);sendPand.setBounds(10, 240, 320, 140);sendButton.setBounds(180, 390, 60, 30);cancelButton.setBounds(260, 390, 60, 30);//设置上面接收框的信息不能更改messArea.setEnabled(false);//设置文本域中字体的效果messArea.setFont(new Font("宋体", Font.BOLD,18));sendArea.setFont(new Font("宋体", Font.BOLD,18));}//设计一个方法 做一些组件之间的相互添加@Overrideprotected void addElements(){//5.将这些组件放在panel里,panel放在frame里panel.add(messPane);panel.add(sendPand);panel.add(sendButton);panel.add(cancelButton);this.add(panel);}//设计一个方法 用来做窗体自己的一些设置 初始位置 不可拖拽@Overrideprotected void setSelf(){//需要在创建出来的同时,设置一下窗口的展示this.setBounds(500, 200, 350, 480);//可以设置窗口不可以拖拽改变大小this.setResizable(false);//设置点击右上角关闭按钮的同时,让程序结束this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// private static final int xxx=3;//其实窗口已经创建出来了,默认效果是隐藏的//需要设置那个窗口的状态 隐藏--->显示//面向对象 窗口的状态-----对象的属性// 设置状态----事情----方法 setXXXXthis.setVisible(true);}
}
package frame;public class Test {public static void main(String[] args) {//1.创建一个QQFrame窗口对象new QQFrame("聊天框");//无参数构造方法}
}
二、客户端与服务器通信
package client;import java.io.*;
import java.net.Socket;
import java.util.Scanner;public class TestClient {public static void main(String[] args) {try {System.out.println("我是客户端");//1.主动访问服务端,访问成功后,即连接成功,获取一个socket对象Socket socket=new Socket("127.0.0.1",9999);//服务器地址(IP) 服务器开放的端口号(port)System.out.println("我成功连接到服务器啦?");//======================================Scanner input=new Scanner(System.in);//2.读取服务器发送过来的消息 读消息/输入流对象//不能自己创建,需要通过socket对象来回去InputStream is = socket.getInputStream();//is其实可以拿去读取消息,is是一个字节型输入流//为了读取字符更加方便,做一个包装InputStreamReader isr=new InputStreamReader(is);//字节--->字符转换流--->最终是个字符//isr其实可以读取中文啦,但是由于对面发送过来的是一行为单位的,isr无法读取一行数据//为了读取一行比较方便,再做一个包装BufferedReader reader = new BufferedReader(isr);//包装本身体现出来一种设计模式——————装饰者模式 23//3.客户端回写点什么 写消息/输出流对象OutputStream os = socket.getOutputStream();PrintWriter writer=new PrintWriter(os);while (true){String value = reader.readLine();System.out.println("消息"+value);System.out.println("回写点什么吧:");String mess=input.nextLine();writer.println(mess);writer.flush();}} catch (IOException e) {e.printStackTrace();}}
}
package server;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;public class TestServer {public static void main(String[] args) {try {System.out.println("===Server start===");//1.开启一个服务//调用构造方法,缺少参数//没法构造对象,接口/抽象类//类中构造方法虽然有,但是都是private(私有化),提供的都是类似工厂一样的方法//构建对象的时候,出现了编译时异常// ArrayIndexOutofBoundsException// NullPointerException// InputMisMatchException// NumberFormatException// ArithmeticException// ClassCastException// StringIndexOutOfBoundsExceptionServerSocket server=new ServerSocket(9999);//0——65535//服务器开发的端口号,为了让客户的数据从这个端口进入到服务器来的//2.开启服务之后,等待某一个客户端过来访问我,需要服务器统一/接收Socket socket = server.accept();System.out.println("有一个客户端跟我连接成功啦");//================================================================Scanner input=new Scanner(System.in);//3.先让服务器跟客户端说一句话————写消息/输出流//不是自己随意创建的输出流,得通过socket来获取OutputStream os = socket.getOutputStream(); //流(读 I/写O) 字节/字符(Reader、Writer)//上述os对象可以写消息了,但是os是一个字节流,发送中文的时候不方便//字节流进行一个包装---->字符流PrintWriter writer=new PrintWriter(os);//4.服务器读取回写的消息 读信息/输入流对象InputStream is = socket.getInputStream();InputStreamReader isr=new InputStreamReader(is);BufferedReader reader=new BufferedReader(isr);while(true){//4.可以发送数据啦System.out.println("说点什么吧:");String mess = input.nextLine();writer.println(mess);writer.flush();//刷新 清空流管道String value = reader.readLine();System.out.println("消息:"+value);}} catch (IOException e) {e.printStackTrace();}}
}
三、客户端发起聊天
四、完成客户端界面交互
优化代码
package frame;import javax.swing.*;//只是发现以后所有的框都是按照刚才那套流程画出来的
//只不过具体的组件,位置,布局都不一样,但是需要做的事情抽象来看都是一样的
//设计一个抽象的规则//模板方法模式 23个设计模式当中的一个//还有一种是:缺省适配器模式 MyFrame(接口 10个) baseFrame(挑一些不重要的实现掉{} 子类去实现一些必要的方法)
public abstract class BaseFrame extends JFrame {public BaseFrame(String title){super(title);}protected abstract void setOther();protected abstract void addElements();protected abstract void addListener();protected abstract void setSelf();
}
package frame;import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.net.Socket;
import java.text.DateFormat;
import java.text.FieldPosition;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;//简单梳理一下关于Swing的技术
//GUI 图形用户接口(规则) Client/Server
//GUI下面有两个接口:AWT Swing。 可以做但很少用来基于Browser/Server HTML <html></html>
//想要利用Swing技术来实现一个窗口的绘制
//里面有JFrame窗体 可看成类似于<body>
//还有JPanel面板 可看成类似于<div><span> 无色透明的容器 做布局管理
//各种组件 按钮 文本框 文本域 理解为HTMl中那些<input type="button">
//JButton按钮 JTextField
//最终肯定是需要有功能 事件-方法 HTML(布局)+CSS(样式)+JS(事件) Tomcat
//事件背后才是我们真正需要实现的强大逻辑/功能//============================================================
//需要自己描述一个类
//可能需要描述属性,方法
//类与类的关系
//继承 泛化(实现) A is a B
// 聚合 组合 A has-a B
// 包含 依赖 A use-a B
public class QQFrame extends BaseFrame{//是一个窗口 类和类之间的关系 A is-a B 继承//构造方法 里面可以放这三个方法,或者这三个方法可以放在代码块,让它在构造方法之前加载public QQFrame(String uid){super(uid);this.uid=uid;//1.真的跟服务器产生一个连接this.start();//2.调用里面的方法this.setOther();this.addElements();this.addListener();this.setSelf();}//1.需要一个窗体/窗口private JFrame frame=new JFrame("聊天框");//GC 边界管理//2.需要一个无色透明的容器--面板private JPanel panel=new JPanel();// 流式管理 可以有多个//3.需要一些聊天窗口的组件//这是两个带滚动条的文本域private JTextArea messArea=new JTextArea();private JScrollPane messPane=new JScrollPane(messArea);//滚动条范围大,里面是包着文本域的private JTextArea sendArea=new JTextArea();private JScrollPane sendPand=new JScrollPane(sendArea);//两个按钮private JButton sendButton=new JButton("发送");private JButton cancelButton=new JButton("取消");//设计一个方法 做一些设置 布局 字体。。@Overrideprotected void setOther(){//4.为了让布局更好的好看一点,我们采用一个自动布局的方式// 自定义布局需要将原有的布局清空panel.setLayout(null);//所有的组件按照自己的设计位置放置messPane.setBounds(10, 10, 320, 220);sendPand.setBounds(10, 240, 320, 140);sendButton.setBounds(180, 390, 60, 30);cancelButton.setBounds(260, 390, 60, 30);//设置上面接收框的信息不能更改messArea.setEnabled(false);//设置文本域中字体的效果messArea.setFont(new Font("黑体", Font.BOLD,18));sendArea.setFont(new Font("黑体", Font.BOLD,18));}//设计一个方法 做一些组件之间的相互添加@Overrideprotected void addElements(){//5.将这些组件放在panel里,panel放在frame里panel.add(messPane);panel.add(sendPand);panel.add(sendButton);panel.add(cancelButton);this.add(panel);}//设计一个方法 给窗口中的某些组件添加事件@Overrideprotected void addListener(){//给取消按钮绑定一个事件---对象(帮你去做) 观察者模式Observer 按钮-目标 做事-观察者对象cancelButton.addActionListener(e->{sendArea.setText("");});//给发送按钮绑定一个事件---sendButton.addActionListener(e -> {try {PrintWriter writer=new PrintWriter(socket.getOutputStream());String message = sendArea.getText();//获取一个系统当前时间Date date=new Date();DateFormat df=new SimpleDateFormat("yyyy-MM-dd kk:mm:ss");String time = df.format(date);writer.println(time+"##@##"+uid+":"+message);//客户端真正发送的消息writer.flush();//发送框文字清空sendArea.setText("");} catch (IOException e1) {e1.printStackTrace();}});}//设计一个方法 用来做窗体自己的一些设置 初始位置 不可拖拽@Overrideprotected void setSelf(){//需要在创建出来的同时,设置一下窗口的展示this.setBounds(500, 200, 350, 480);//可以设置窗口不可以拖拽改变大小this.setResizable(false);//设置点击右上角关闭按钮的同时,让程序结束this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// private static final int xxx=3;//其实窗口已经创建出来了,默认效果是隐藏的//需要设置那个窗口的状态 隐藏--->显示//面向对象 窗口的状态-----对象的属性// 设置状态----事情----方法 setXXXXthis.setVisible(true);}//=============================================================================//因为当前的QQFrame就是那个客户端,// 所以客户端需要有一个uidprivate String uid;//所以客户端需要一个socketprivate Socket socket;//====================================================public void start(){try {//1.主动访问服务端socket=new Socket("127.0.0.1",9999);//2.客户端将自己的uid写给服务器PrintWriter writer=new PrintWriter(socket.getOutputStream());writer.println(uid);writer.flush();//3.将socket分别交给两个小弟,读/写ClientReader cr=new ClientReader();cr.start();} catch (IOException e) {e.printStackTrace();}}//====================================================//客户端读线程(剩下的那个小弟)---只管客户端自己用//1.不想让别人看见我客户端自己不干活,还有一个小弟帮我//2.节省一个类文件//3.客户端读线程,读取的数据不是在控制台展示的,是需要展示在客户端的文本域中// 最主要才是这个问题,内部类中直接使用外部类成员private class ClientReader extends Thread{//频繁的追加新的字符串,不能让聊天框中的文字清空StringBuilder result=new StringBuilder();@Overridepublic void run(){//读取try {InputStream is=socket.getInputStream();InputStreamReader isr=new InputStreamReader(is);BufferedReader reader=new BufferedReader(isr);//可以读取一行while (true){String value=reader.readLine();//time##@##uid:messagevalue.replace("##@##", "\r\n");result.append(value);result.append("\n");//找到那个文本域,value放里即可messArea.setText(result.toString());}} catch (IOException e) {//e.printStackTrace();System.out.println("服务器宕机啦");}}}}
package frame;import frame.QQFrame;public class TestClient {public static void main(String[] args) {//1.创建客户端new QQFrame("zzt");new QQFrame("dmc");new QQFrame("Ella");}
// public static void main(String[] args) {
// try {
// System.out.println("我是客户端");
// //1.主动访问服务端,访问成功后,即连接成功,获取一个socket对象
// Socket socket=new Socket("127.0.0.1",9999);//服务器地址(IP) 服务器开放的端口号(port)
// System.out.println("我成功连接到服务器啦?");
// //======================================
// Scanner input=new Scanner(System.in);
//
// //2.读取服务器发送过来的消息 读消息/输入流对象
// //不能自己创建,需要通过socket对象来回去
// InputStream is = socket.getInputStream();
// //is其实可以拿去读取消息,is是一个字节型输入流
// //为了读取字符更加方便,做一个包装
// InputStreamReader isr=new InputStreamReader(is);//字节--->字符转换流--->最终是个字符
// //isr其实可以读取中文啦,但是由于对面发送过来的是一行为单位的,isr无法读取一行数据
// //为了读取一行比较方便,再做一个包装
// BufferedReader reader = new BufferedReader(isr);//包装本身体现出来一种设计模式——————装饰者模式 23
// //3.客户端回写点什么 写消息/输出流对象
// OutputStream os = socket.getOutputStream();
// PrintWriter writer=new PrintWriter(os);
//
// while (true){
// String value = reader.readLine();
// System.out.println("消息"+value);
//
// System.out.println("回写点什么吧:");
// String mess=input.nextLine();
// writer.println(mess);
// writer.flush();
// }
// } catch (IOException e) {
// e.printStackTrace();
// }
//
// }
}
package server;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;//服务器类
public class Server {//属性集合----Map<String,User>static HashMap<String,User> userBox=new HashMap();public void start(int port){try {System.out.println("====server start===");ServerSocket server=new ServerSocket(port);while (true){//服务器开启,一直等待客户端Socket socket = server.accept();//将socket对象存入map集合//读取客户端发来的Uid 服务端可以获取socket,但是没有Uid(客户端发送过来)//<Uid,User(Uid,Socket)>InputStream is = socket.getInputStream();InputStreamReader isr=new InputStreamReader(is);BufferedReader reader=new BufferedReader(isr);String uid = reader.readLine();//构建一个User对象User user=new User(uid, socket);userBox.put(uid, user);System.out.println(uid+"成功连接到服务器啦");//将这个socker交给一个小弟来负责处理ServerThread st=new ServerThread(user);st.start();}} catch (IOException e) {e.printStackTrace();}}
}
package server;import java.io.*;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;//服务端线程
public class ServerThread extends Thread{private User user;public ServerThread(User user){this.user=user;}@Overridepublic void run(){try {//1.读取刚才那个socket客户端发送过来的数据InputStream is = user.getSocket().getInputStream();InputStreamReader isr=new InputStreamReader(is);BufferedReader reader=new BufferedReader(isr);while (true){//服务器从客户端那里读取过来的真实数据/消息String message =reader.readLine();System.out.println("接收到"+user.getUid()+"xxx发送过来的"+message);//2.将数据转发给其他socket对应的客户端------群聊 map遍历 User(socket)//想要转发出去,需要找到那个mapMap<String,User> map=Server.userBox;//<uid,user>//将map集合遍历,获取里面全部的user,拿到每一个user里面的socket--->Set keySet = map.keySet();Iterator it = keySet.iterator();while (it.hasNext()){String uid= (String)it.next();User user=map.get(uid);PrintWriter pw=new PrintWriter(user.getSocket().getOutputStream());pw.println(message);pw.flush();}}} catch (IOException e) {//e.printStackTrace();System.out.println(user.getUid()+"下线啦");}}
}
package server;public class TestServer {public static void main(String[] args) {//1.启动一个服务Server server=new Server();//2.启动即可server.start(9999);}
// public static void main(String[] args) {
// try {
// System.out.println("===Server start===");
// //1.开启一个服务
// //调用构造方法,缺少参数
// //没法构造对象,接口/抽象类
// //类中构造方法虽然有,但是都是private(私有化),提供的都是类似工厂一样的方法
// //构建对象的时候,出现了编译时异常
// // ArrayIndexOutofBoundsException
// // NullPointerException
// // InputMisMatchException
// // NumberFormatException
// // ArithmeticException
// // ClassCastException
// // StringIndexOutOfBoundsException
// ServerSocket server=new ServerSocket(9999);//0——65535//服务器开发的端口号,为了让客户的数据从这个端口进入到服务器来的
// //2.开启服务之后,等待某一个客户端过来访问我,需要服务器统一/接收
// Socket socket = server.accept();
// System.out.println("有一个客户端跟我连接成功啦");
// //================================================================
//
// Scanner input=new Scanner(System.in);
//
// //3.先让服务器跟客户端说一句话————写消息/输出流
// //不是自己随意创建的输出流,得通过socket来获取
// OutputStream os = socket.getOutputStream(); //流(读 I/写O) 字节/字符(Reader、Writer)
// //上述os对象可以写消息了,但是os是一个字节流,发送中文的时候不方便
// //字节流进行一个包装---->字符流
// PrintWriter writer=new PrintWriter(os);
//
//
// //4.服务器读取回写的消息 读信息/输入流对象
// InputStream is = socket.getInputStream();
// InputStreamReader isr=new InputStreamReader(is);
// BufferedReader reader=new BufferedReader(isr);
//
// while(true){
// //4.可以发送数据啦
// System.out.println("说点什么吧:");
// String mess = input.nextLine();
// writer.println(mess);
// writer.flush();//刷新 清空流管道
//
// String value = reader.readLine();
// System.out.println("消息:"+value);
// }
// } catch (IOException e) {
// e.printStackTrace();
// }
//
//
//
// }
}
package server;import java.net.Socket;//服务器端自己创建的一个类型
//目的:为了将一个用户名和这个用户对应的socket对象包括包装在一起
//每一个User对象,其实就是一个存储数据的容器
public class User {private String uid;private Socket socket;public User(String uid, Socket socket) {this.uid = uid;this.socket = socket;}public String getUid() {return uid;}public Socket getSocket() {return socket;}
}
创建专属聊天室练习(客户端与服务端通信|客户端界面交互)相关推荐
- 浅议C#客户端和服务端通信的几种方法:Rest和GRPC和其他
本文来自:https://michaelscodingspot.com/rest-vs-grpc-for-asp-net/ 浅议C#客户端和服务端通信的几种方法:Rest和GRPC 在C#客户端和C# ...
- socket java 客户端_Java基于socket实现的客户端和服务端通信功能完整实例
本文实例讲述了Java基于socket实现的客户端和服务端通信功能.分享给大家供大家参考,具体如下: 以下代码参考马士兵的聊天项目,先运行ChatServer.java实现端口监听,然后再运行Chat ...
- Netty即是服务端又是客户端,服务端和客户端相互对应
Netty即是服务端又是客户端,服务端和客户端相互对应. 具体功能细节是: 上游有一个服务,会主动发送消息给我中间件平台.中间件平台既有服务端也有客户端.通过下游客户端连接进来的客户端和中间件传下去的 ...
- redis源码客户端和服务端通信过程
最近想学习一下redis源码,先看一下redis通信流程.由于功力有限,不足之处望大家指正.服务端和客户端通信,一般都是服务端先启动,那先从服务端的源码看起. 首先启动服务端会做一些初始化动作,初始化 ...
- Java--Socket客户端,服务端通信
1.客户端接受服务端的消息并打印: 客户端: import java.io.BufferedReader; import java.io.IOException; import java.io.Inp ...
- ssl客户端与服务端通信的demo
服务端程序流程 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <errno.h> 4 #include ...
- 客户端和服务端通信原理
客户端和服务端 客户端:可以向服务端发起请求的,并且接受返回的内容的进行处理 服务器端:能够接受客户端的请求,并且把相关资源信息返回给客户端的 web 服务站点 详细 url 地址解析 DNS 服务器 ...
- 【Android 开发】: Android客户端与服务端之间使用JSON交互数据。
在前面的两讲中,我们讲解了JSON数据格式的一些基本知识,以及做一些小Demo,这一讲我们在前面的基础上来做一个综合的可扩展的Demo,主要是针对Android客户端解析服务端传递过来的JSON数据. ...
- Java中Socket实现客户端和服务端通信(多线程实现全双工通信)
效果图 目录结构 服务端Server package server;import thread.SocketReader; import thread.SocketWrite;import java. ...
- python客户端和服务端通信
1.客户端 `import socket client=socket.socket(type=socket.SOCK_DGRAM) ip_port=('10.10.42.68',9000) while ...
最新文章
- 手把手玩转协同编辑(1):AST (Address Space Transformation)地址空间转换算法 基本介绍...
- python函数太多_numpy Loadtxt函数似乎消耗了太多内存
- 终于从yahoo手中把域名抢救出来了
- FZU 2082 过路费(树链剖分 边权)题解
- Owin服务无法启动问题整理
- C# winform post 请求指定 url
- linux mate桌面主题下载_5个适用于Linux的最佳图标主题
- 关于K2路由破解锐捷校园认证这件事(ZZU版)
- 矩阵特征值的求解例子
- python合并excel工作簿_ExcelPython合并处理Excel工作簿、工作表
- 未来智能营销时代到来,人工智能营销系统方兴未艾
- 荷马史诗——解题报告
- 经营三类医疗器械不使用计算机,第三十条经营第三类医疗器械的企业,应当具有符合医疗器械经营质量管理要求的计算机信息管理系统,保证经营的产品可追溯。计算机信息管理系统应当具有以下功能:...
- 使用google.zxing制作条形码和二维码
- 阿里云ECS建站教程(超详细图文教程)
- 音视频从入门到精通——FFmpeg之swr_convert音频重采样函数分析
- XSS Challenges xss-quiz.int21h.jp
- ggplot2 annotate()函数
- oracle 查询数据库时区,[原创]数据库时区与操作系统不一致时的解决方法
- MyBatis配置文件,节点顺序