srgagagaga212
2022-06-22 19:06
采纳率: 100%
浏览 13

Java实现实时聊天互动程序,这怎么解决问题

ServerChatMain




package pp.chat;

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.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Properties;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;





//如果一个类,需要有界面的显示,那么该类就需要继承自JFrame,此时,该类就可以被称为一个“窗体类”
//1.定义JFrame窗体中的组件
//2.在构造方法中初始化窗体的组件
//3.使用网络编程完成数据的传输(TCP,UDP协议)
//4.实现“发送”按钮的监听点击事件,需要注意的是,文本域拼接数据时,实现自己换行,不要在发送数据中使用System.lineSeparator()换行。这样会导致无法辨别换行
//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静态代码块读取外部配置文件
    //特点1:在类加载的时候,自动执行。
    //特点2:一个类只会被加载一次,因此静态代码块在程序中仅会被执行一次。
    static{
        Properties prop = new Properties();
        
        try{
            //加载
            prop.load(new FileReader("char.properties"));
            
            //给属性赋值
            serverPort = 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.add(jsp,BorderLayout.CENTER);
        this.add(jp,BorderLayout.SOUTH);
        
        //注意:需要设置“标题,大小,位置,关闭,是否可见
        this.setTitle("qq聊天 服务端");
        this.setSize(300,300);
        this.setLocation(300,300);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//窗体关闭程序就退出
        this.setVisible(true);
        
        /**********************TCP 服务端 start**********************/
        //给“发送”按钮绑定一个监听点击事件
        jb.addActionListener(this);
        //给文本框绑定一个键盘点击事件
        jtf.addKeyListener(this);
        try{
            //1.创建一个服务端的套接字
        ServerSocket serverSocket = new ServerSocket(serverPort);
        
        //2.等待客户端的连接
        Socket socket = serverSocket.accept();
        
        //3.获取 socket 通道的输入流(输出流是实现读取数据,如何读取?一行一行读取)BufferedReader ->readLine();
        //InputStream in = socket.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        
        
    
        //4.获取 socket 通道的输出流(输出流实现写出数据,也是写一行,换一行,刷新)BufferedWrite -> newLine();
        //问题:什么时候需要写出数据???当用户点击“发送”按钮的时候才需要写出数据
        bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        
        //循环读取数据,并拼接到文本域中
        String line = null;
        while((line = br.readLine())!= null){
            //将读取的数据拼接到文本域中显示
            jta.append(line + System.lineSeparator());
            
        }
        
        
        
        //5.关闭 serverSocket 通道
        serverSocket.close();
        
        }catch(IOException e1){
            e1.printStackTrace();
        }
        
        
        
        
        /**********************TCP 服务端 end**********************/
        
    
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        //System.out.println("发送按钮被点击了。。。");
        sendDataToSocket();

}
    //行为
    
    @Override
    public void keyPressed(KeyEvent e) {
        //回车键
        if(e.getKeyCode() == KeyEvent.VK_ENTER){
            //发送数据到socket通道中
            sendDataToSocket();
        }
            
    }
    
    
    //定义一个方法,实现将数据发送到socket通道中
    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();
    
    //5.清空文本框内容
    jtf.setText("");
}catch (IOException e1){
    e1.printStackTrace();
}
    }
    @Override
    public void keyReleased(KeyEvent e) {
    }
    

    @Override
    public void keyTyped(KeyEvent e) {
    }
}

ClientChatMain

package pp.chat;

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.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Properties;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

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;
    
    //输出流
    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.add(jsp,BorderLayout.CENTER);
        this.add(jp,BorderLayout.SOUTH);
        
        //注意:需要设置“标题,大小,位置,关闭,是否可见
        this.setTitle("qq聊天 客户端");
        this.setSize(300,300);
        this.setLocation(600,300);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
        
        
        /**********************TCP 客户端 start**********************/
        //给发送按钮绑定一个监听点击事件
        jb.addActionListener(this);
        //给文本框绑定一个键盘点击事件
        jtf.addKeyListener(this);
        try{
            //1.创建一个客户端的套接字(尝试连接)
        Socket socket = new Socket(clientIP,clientPort);
        
        
        //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){
            //发送数据到socket通道
            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() 与 System.lineSeparator() 两个换行导致使用BufferedReader一行一行读取时,无法正确的辨别需要的换行
                    bw.newLine();
                    bw.flush();
                    //5.清空
                    jtf.setText("");
                }catch (IOException e1){
                    e1.printStackTrace();
                }
                
    }

    @Override
    public void keyReleased(KeyEvent e) {
    }

    @Override
    public void keyTyped(KeyEvent e) {
    }
    
    
}


img

结果
没有连接成功,不能成功发送消息
并且文本框没有刷新

img

还有一堆看不懂的

img

1条回答 默认 最新