超详细带你用Java实现QQ的聊天功能
时间:2022-10-12 03:30:01 sitemap
个人名片:
??作者简介:一名学生
???个人主页:hmm.
???系列专栏:零基础学java ----- 重识c语言
??每日一句话:只要还有明天,今天就永远是起点。
前言:???
最近有很多朋友问小新有没有好用的刷题网站,想提高自己的能力**
>**经过小欣的仔细思考和个人经验,推荐超实用**??(点击访问牛客网)??
>*大厂面试真题丰富,各种算法由易到难递进,专题库应有尽有,不快来体验体验**???
文章目录
- 第一步:完成界面构建
- 第二步:TPC通信的思路和步骤
-
- TCP协议??
- TCP 服务端 具体步骤(类似客户端)
- TCP实现通信步骤代码:
- 点击发送按钮实现数据传输
- 第三步:实现回车键发送数据(类似客户端)
- 全部代码:??
-
第一步:完成界面构建
要求:
- 创建两个窗口:一个客户端,一个服务端,完成代码书写
步骤:
1.定义JFrame窗体组件:文本域、滚动条、面板、文本框、按钮
//属性 //文本域 private JTextArea jta; //滚动条 private JScrollPane jsp; //面板 private JPanel jp; //文本框 private JTextField jtf; //按钮 private JButton jb;
2.构造方法中初始化窗口的组件:
//构造方法 public ServerChatMain(){ ///初始化组件 jta = new JTextArea(); ///默认设置文本域不能编辑 jta.setEditable(false); //注:文本域需要添加到滚动条中,实现滚动效果 jsp =new JScrollPane(jta); ///初始化面板 jp = new JPanel(); jtf = new JTextField(10); jb=new JButton("发送"); //注意在面板中添加文本框和按钮 jp.add(jtf); jp.add(jb);
- 注:所有滚动条和面板都需要添加到窗体中,以继承窗体的属性this就是窗体
this.add(jsp, BorderLayout.CENTER);//BorderLayout--边框布局 this.add(jp,BorderLayout.SOUTH);
4.设置标题,大小,位置,关闭,是否可见
//注:需要设置标题,大小,位置,关闭,是否可见 this.setTitle("QQ聊天服务端"); this.setSize(400,300); this.setLocation(700,300); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);///窗体关闭,程序退出 this.setVisible(true);//设置窗体可见 }
这样,我们就完成了服务端QQ搭建聊天界面窗口:
注意:JTextArea文本域不能写。
客户端类似于服务端代码,这里就不一一展示了
编写代码后,操作效果如下图所示:
第二步:TPC通信的思路和步骤
利用网络编程完成数据点的传输(TCP,UDP协议)
TCP协议??
TCP 是面向连接的运输层协议。使用应用程序 TCP 在协议建立之前 TCP 连接。传输数据后,必须释放已建立的数据 TCP 连接
每一条 TCP 连接只能有两个端点,每个端点 TCP 连接只能是点对点(一对一)
TCP 提供可靠交付的服务。通过 TCP 连接传输的数据,无错误,无丢失,无重复,并按顺序到达
TCP 提供全双工通信。TCP 允许通信双方的应用程序随时发送数据。TCP 发送缓存和接收缓存用于临时存储双向通信的数据
面向字节流。TCP 流是指流入过程或流出过程的字节序列
TCP 服务端 具体步骤(类似客户端)
具体步骤:
-
1.创建服务端的套接字
-
2.等待客户端连接
-
3.获取socket输入流(输入6是读取数据,一行一行读取)BufferedReader->readLine();
-
4.获取socket 通道的输出流(输出流实现数据的写作,也是写一行换一行刷新)BufferedWriter->newLine();
-
5.关闭socket 通道
TCP实现通信步骤代码:
try { //1.创建服务端的套接字 ServerSocket serverSocket = new ServerSocket(8888); //2.等待客户端连接 Socket socket = serverSocket.accept(); //3.获取socket输入流(输入六是读取数据,一行一行读取)BufferedReader->readLine(); //InputStream in = socket.getInputStream(); BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream())); //4.获取socket 通道输出流(输出流可以写出数据,也写一行换一行,刷新)BufferedWriter->newLine(); ///用户点击发送按钮时写数据 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); ///循环读取数据,拼接到文本域 String line = null; while((line = br.readLine())!=null){ ///将读取的数据拼接到文本域显示 jta.append(line System.lineSeparator()); } //5.关闭socket 通道 serverSocket.close(); }catch (IOException e) { e.printStackTrace(); }
点击发送按钮实现数据传输
@Override
public void actionPerformed(ActionEvent actionEvent) {
System.out.println("发送按钮被点击了");
}
步骤:
1.获取文本框中发送的内容
2.拼接需要发送的数据内容
3.自己也要显示
4.发送
5.清空文本框内容
@Override
public void actionPerformed(ActionEvent actionEvent) {
//System.out.println("发送按钮被点击了");
//1.获取文本框中发送的内容
String text = jtf.getText();
//2.拼接需要发送的数据内容
text = "服务端对客户端说:"+text;
//3.自己也要显示
jta.append(text);
//4.发送
try {
bw.write(text);
bw.newLine();//换行刷新
bw.flush();
//5.清空文本框内容
jtf.setText("");
} catch (IOException e) {
e.printStackTrace();
}
}
第三步:实现回车键发送数据(客户端类似)🐳
首先要实现一个接口
public class ClientChatMain extends JFrame implements ActionListener, KeyListener {
@Override
public void keyPressed(KeyEvent e) {
//回车键
// System.out.println(e);
//发送数据到socket 同道中
if(e.getKeyCode()==KeyEvent.VK_ENTER) {
sendDataToSocket();
}
全部代码:🐲
服务端:
package com.ithmm.chat; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.util.Properties; //说明:如果一个类,需要有界面的显示,那么这个类就需要继承JFrame,此时,该类可以被成为一个窗体类 /*步骤: 1.定义JFrame窗体中的组件 2.在构造方法中初始化窗口的组件 3.使用网络编程完成数据的链接(TPC,UDP 协议) 4.实现"发送”按钮的监听点击事件 5.实现“回车键”发送数据 */ public class ServerChatMain extends JFrame implements ActionListener, KeyListener { public static void main(String[] args) { //调用构造方法 new ServerChatMain(); } //属性 //文本域 private JTextArea jta; //滚动条 private JScrollPane jsp; //面板 private JPanel jp; //文本框 private JTextField jtf; //按钮 private JButton jb; //输出流(成员变量) private BufferedWriter bw = null; //服务端的端口号 //private static int serverPort; //使用static静态方法读取外部京台文件 //static代码块特点:1.在类加载的时候自动执行 //特点2:一个类会被加载一次,因此静态代码块在程序中仅会被执行一次 /*static{ Properties prop = new Properties(); try { //加载 prop.load(new FileReader("chat.properties")); //给属性赋值 Integer.parseInt(prop.getProperty("serverPort")); } catch (IOException e) { e.printStackTrace(); } }*/ //构造方法 public ServerChatMain(){ //初始化组件 jta = new JTextArea(); //设置文本域默认不可编辑 jta.setEditable(false); //注意:需要将文本域添加到滚动条中,实现滚动效果 jsp =new JScrollPane(jta); //初始化面板 jp = new JPanel(); jtf = new JTextField(10); jb=new JButton("发送"); //注意:需要将文本框与按钮添加到面板中 jp.add(jtf); jp.add(jb); //注意:需要将滚动条与面板全部添加到窗体中,继承了窗体的属性,这里this就是窗体 this.add(jsp, BorderLayout.CENTER);//BorderLayout--边框布局 this.add(jp,BorderLayout.SOUTH); //注意:需要设置”标题“,大小,位置,关闭,是否可见 this.setTitle("QQ聊天服务端"); this.setSize(400,300); this.setLocation(700,300); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//窗体关闭,程序就退出 this.setVisible(true);//设置窗体可见 /**************** TCP 服务端 Start *********************/ //给发送按钮绑定一个监听点击事件 jb.addActionListener(this); //给文本框绑定一个
键盘点击事件 jtf.addKeyListener(this); try { //1.创建一个服务端的套接字 ServerSocket serverSocket = new ServerSocket(8888); //2.等待客户端连接 Socket socket = serverSocket.accept(); //3.获取socket通道的输入流(输入六是实现读取数据的,一行一行读取)BufferedReader->readLine(); //InputStream in = socket.getInputStream(); BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream())); //4.获取socket 通道的输出流(输出流实现写出数据,也是写一行换一行,刷新)BufferedWriter->newLine(); //当用户点击发送按钮的时候写出数据 bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); //循环读取数据并拼接到文本域 String line = null; while((line = br.readLine())!=null){ //将读取的数据拼接到文本域中显示 jta.append(line+System.lineSeparator()); } //5.关闭socket 通道 serverSocket.close(); }catch (IOException e) { e.printStackTrace(); } /**************** TCP 服务端 end *********************/ } @Override public void actionPerformed(ActionEvent actionEvent) { //System.out.println("发送按钮被点击了"); sendDataToSocket(); } //行为 @Override public void keyPressed(KeyEvent e) { //回车键 // System.out.println(e); //发送数据到socket 同道中 if(e.getKeyCode()==KeyEvent.VK_ENTER) { sendDataToSocket(); } } //定义一个方法,实现将数据发送到socket通道中 private void sendDataToSocket(){ //1.获取文本框中发送的内容 String text = jtf.getText(); //2.拼接需要发送的数据内容 text = "服务端对客户端说:"+text; //3.自己也要显示 jta.append(text+System.lineSeparator()); //4.发送 try { bw.write(text); bw.newLine();//换行刷新 bw.flush(); //5.清空文本框内容 jtf.setText(""); } catch (IOException e) { e.printStackTrace(); } } @Override public void keyTyped(KeyEvent keyEvent) { } @Override public void keyReleased(KeyEvent keyEvent) { } }
客户端:
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
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.util.Properties;
//说明:如果一个类,需要有界面的显示,那么这个类就需要继承JFrame,此时,该类可以被成为一个窗体类
/*步骤:
1.定义JFrame窗体中的组件
2.在构造方法中初始化窗口的组件
*/
public class ClientChatMain extends JFrame implements ActionListener, KeyListener {
public static void main(String[] args) {
//调用构造方法
new ClientChatMain();
}
//属性
//文本域
private JTextArea jta;
//滚动条
private JScrollPane jsp;
//面板
private JPanel jp;
//文本框
private JTextField jtf;
//按钮
private JButton jb;
//s输出流
private BufferedWriter bw =null;
//客户端的IP地址
// private static String clientIp;
//客户端的port端口号
// private static int clientPort;
//静态代码块加载外部配置文件
/* static{
Properties prop = new Properties();
try {
prop.load(new FileReader("chat.properties"));
clientIp = prop.getProperty("clientIp");
clientPort =Integer.parseInt( prop.getProperty("clientPort"));
} catch (IOException e) {
e.printStackTrace();
}
}*/
//构造方法
public ClientChatMain(){
//初始化组件
jta = new JTextArea();
//设置文本域默认不可编辑
jta.setEditable(false);
//注意:需要将文本域添加到滚动条中,实现滚动效果
jsp =new JScrollPane(jta);
//初始化面板
jp = new JPanel();
jtf = new JTextField(10);
jb=new JButton("发送");
//注意:需要将文本框与按钮添加到面板中
jp.add(jtf);
jp.add(jb);
//注意:需要将滚动条与面板全部添加到窗体中,继承了窗体的属性,这里this就是窗体
this.add(jsp, BorderLayout.CENTER);//BorderLayout--边框布局
this.add(jp,BorderLayout.SOUTH);
//注意:需要设置”标题“,大小,位置,关闭,是否可见
this.setTitle("QQ聊天客户端");
this.setSize(400,300);
this.setLocation(700,300);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//窗体关闭,程序就退出
this.setVisible(true);//设置窗体可见
/**************** TCP 客户端 Start *********************/
//给发送按钮绑定一个监听点击事件
jb.addActionListener(this);
//给文本框绑定一个键盘键
jtf.addKeyListener(this);
try {
//1.创建一个客户端的套接字(尝试连接)
Socket socket = new Socket("127.0.0.1",8888);
//2.获取socket通道的输入流
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//3.获取socket 通道的输出流
bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
//循环读取数据,并拼接到文本域
String line = null;
while((line = br.readLine())!=null){
jta.append(line + System.lineSeparator());
}
//4.关闭socket 通道
socket.close();
}catch (Exception e){
e.printStackTrace();
}
/**************** TCP 客户端 end *********************/
}
@Override
public void actionPerformed(ActionEvent e) {
sendDataToSocket();
}
//行为
@Override
public void keyPressed(KeyEvent e) {
//回车键
if(e.getKeyCode() == KeyEvent.VK_ENTER){
//发送数据
sendDataToSocket();
}
}
private void sendDataToSocket(){
//1.获取文本框需要发送内容
String text = jtf.getText();
//2.拼接内容
text = "客户端对服务端说"+text;
//3.自己显示
jta.append(text+System.lineSeparator());
try {
//4.发送
bw.write(text);
bw.newLine();//换行加刷新
bw.flush();
bw.write(text);
//5.清空
jtf.setText("");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
}
}
接口类:
public interface addActistener {
}
public interface addActionListener {
}
兄弟们,三连支持一下!!!