无法将字符串从一个帧发送到另一个帧

时间:2017-08-20 16:34:32

标签: java multithreading swing sockets

我一直在尝试为计算机中的帧之间的端到端消息传输创建聊天程序。但不知何故它不起作用。没有错误或警告。我一直在摸着头大约2个小时。用户界面和其他组件工作正常,我无法在互联网上找到任何答案。 有一个客户端脚本。

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import javax.swing.*;

class ChatClient extends JFrame implements ActionListener,FocusListener{
  JButton button;
  JLabel label;
  JTextField text;
  Socket socket;
  String hostname = "localhost";
  final int portno = 3000;
  PrintWriter out;
  BufferedReader bin;
  int y=10;
  String defaultMessage = "Enter your message..";
  public ChatClient(){
    try{
      makeUI();
      socket = new Socket(hostname,portno);
      out = new PrintWriter(socket.getOutputStream());
      bin = new BufferedReader(new InputStreamReader(socket.getInputStream()));
      new ClientThread().start();
    }catch(Exception ae){
      System.out.println("Error! --> "+ae.getMessage());
    }
  }
  public void makeUI(){
    setTitle("FIreFly-Client");
    text = new JTextField(defaultMessage);
    text.setBounds(10,620,295,40);
    text.addFocusListener(this);
    add(text);
    button = new JButton("SEND");
    button.setBounds(310,620,80,40);
    button.setForeground(Color.WHITE);
    button.setBackground(Color.decode("#11A458"));
    button.setFocusPainted(false);
    button.addActionListener(this);
    add(button);
    setSize(400,700);
    setLayout(null);
    setVisible(true);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  }
  public void focusGained(FocusEvent ae){
    if(text.getText().equals(defaultMessage)){
        text.setText("");
    }
  }
  public void focusLost(FocusEvent ae){
    if(text.getText().isEmpty()){
      text.setText(defaultMessage);
    }
  }
  public void actionPerformed(ActionEvent ae){
    if(!text.getText().isEmpty()){
      if(!text.getText().equals(defaultMessage)){
        out.println(text.getText());
        label = new JLabel(text.getText());
        label.setBounds(10,y,380,20);
        y = y+20;
        add(label);
        revalidate();
        repaint();
      }
    }
  }
  public static void main(String []args){
    try{
        new ChatClient();
    }catch(Exception ae){
      System.out.println("Error! --> "+ae.getMessage());
    }
  }
  class ClientThread extends Thread{
    public void run(){
      String receive;
      try{
        while(true){
          receive = bin.readLine();
          if(!receive.isEmpty()){
            System.out.println(receive);
            label = new JLabel(receive);
            label.setBounds(10,y,380,20);
            y = y+20;
            label.setHorizontalAlignment(SwingConstants.RIGHT);
            add(label);
            revalidate();
            repaint();
          }
        }
      }catch(Exception ae){
        ae.printStackTrace();
      }
    }
  }
}

程序的服务器部分看起来像,

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import javax.swing.*;

class ChatServer extends JFrame implements ActionListener,FocusListener{
  JButton button;
  JLabel label;
  JTextField text;
  Socket socket;
  ServerSocket ss;
  String hostname = "localhost";
  final int portno = 3000;
  PrintWriter out;
  BufferedReader bin;
  int y=10;
  String defaultMessage = "Enter your message..";
  public ChatServer(){
    try{
      makeUI();
      ss = new ServerSocket(portno);
      socket = ss.accept();
      out = new PrintWriter(socket.getOutputStream());
      bin = new BufferedReader(new InputStreamReader(socket.getInputStream()));
      new ServerThread().start();
    }catch(Exception ae){
      System.out.println("Error! --> "+ae.getMessage());
    }
  }
  public void makeUI(){
    setTitle("FireFly-Server");
    text = new JTextField(defaultMessage);
    text.setBounds(10,620,295,40);
    text.addFocusListener(this);
    add(text);
    button = new JButton("SEND");
    button.setBounds(310,620,80,40);
    button.setForeground(Color.WHITE);
    button.setBackground(Color.decode("#11A458"));
    button.setFocusPainted(false);
    button.addActionListener(this);
    add(button);
    setSize(400,700);
    setLayout(null);
    setVisible(true);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  }
  public void focusGained(FocusEvent ae){
    if(text.getText().equals(defaultMessage)){
        text.setText("");
    }
  }
  public void focusLost(FocusEvent ae){
    if(text.getText().isEmpty()){
      text.setText(defaultMessage);
    }
  }
  public void actionPerformed(ActionEvent ae){
    if(!text.getText().isEmpty()){
      if(!text.getText().equals(defaultMessage)){
        System.out.println(text.getText());
        out.println(text.getText());
        label = new JLabel(text.getText());
        label.setBounds(10,y,380,20);
        y = y+20;
        add(label);
        revalidate();
        repaint();
      }
    }
  }
  public static void main(String []args){
    try{
        new ChatServer();
    }catch(Exception ae){
      System.out.println("Error! --> "+ae.getMessage());
    }
  }
  class ServerThread extends Thread{
    public void run(){
      String receive;
      try{
        while(true){
          receive = bin.readLine();
          if(!receive.isEmpty()){
            System.out.println(receive);
            label = new JLabel(receive);
            label.setBounds(10,y,380,20);
            y = y+20;
            label.setHorizontalAlignment(SwingConstants.RIGHT);
            add(label);
            revalidate();
            repaint();
          }
        }
      }catch(Exception ae){
        ae.printStackTrace();
      }
    }
  }
}

有人可以告诉我它有什么问题吗?

2 个答案:

答案 0 :(得分:1)

您需要在调用println后刷新输出流,否则它将位于输出流缓冲区中,并且永远不会被发送。

out.println(text.getText());
out.flush(); // add this

将刷新添加到两个程序中。

客户端gui可能看起来像:

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedReader;
import java.io.PrintWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.List;
import java.util.concurrent.ExecutionException;

import javax.swing.*;

@SuppressWarnings("serial")
public class ChatClient2 extends JPanel {
    private static final int VIS_ROW_CNT = 25;
    private static final String HOST_NAME = "localhost";
    private static final int PORT_NO = 3000;
    private DefaultListModel<String> listModel = new DefaultListModel<>();
    private JList<String> jList = new JList<>(listModel);
    private SendAction sendAction = new SendAction("Send");
    private JButton sendButton = new JButton(sendAction);
    private JTextField textField = new JTextField(20);
    private PrintWriter out;

    public ChatClient2(Socket socket) throws IOException {
        out = new PrintWriter(socket.getOutputStream());
        SocketWorker worker = new SocketWorker(socket);
        worker.addPropertyChangeListener(new WorkerListener());
        worker.execute();

        jList.setPrototypeCellValue("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
        jList.setVisibleRowCount(VIS_ROW_CNT);
        JScrollPane scrollPane = new JScrollPane(jList);
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

        textField.setAction(sendAction);
        JPanel bottomPanel = new JPanel();
        bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.LINE_AXIS));
        bottomPanel.add(textField);
        bottomPanel.add(sendButton);

        setLayout(new BorderLayout());
        add(scrollPane);
        add(bottomPanel, BorderLayout.PAGE_END);
    }

    public void lineToGui(String line) {
        listModel.addElement(line);
    }

    private class SendAction extends AbstractAction {
        public SendAction(String name) {
            super(name);
            int mnemonic = (int) name.charAt(0);
            putValue(MNEMONIC_KEY, mnemonic);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            String text = textField.getText();
            if (!text.trim().isEmpty()) {
                out.println(text);
                out.flush();
                lineToGui("Me: " + text);
            }
            textField.selectAll();
            textField.requestFocusInWindow();
        }
    }

    private class SocketWorker extends SwingWorker<Void, String> {
        private BufferedReader bin;

        public SocketWorker(Socket socket) throws IOException {
            InputStreamReader isr = new InputStreamReader(socket.getInputStream());
            bin = new BufferedReader(isr);
        } 

        @Override
        protected Void doInBackground() throws Exception {
            String line = null;
            while ((line = bin.readLine()) != null) {
                publish(line);
            }
            return null;
        }

        @Override
        protected void process(List<String> chunks) {
            for (String line : chunks) {
                lineToGui("Server: " + line);
            }
        }
    }

    private class WorkerListener implements PropertyChangeListener {
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
                @SuppressWarnings("rawtypes")
                SwingWorker worker = (SwingWorker) evt.getSource();
                try {
                    worker.get();
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        try {
            Socket socket = new Socket(HOST_NAME, PORT_NO);
            SwingUtilities.invokeLater(() -> createAndShowGui(socket));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void createAndShowGui(Socket socket) {
        ChatClient2 mainPanel = null;
        try {
            mainPanel = new ChatClient2(socket);
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(-1);
        }
        JFrame frame = new JFrame("ChatClient2");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

答案 1 :(得分:0)

您应该使用EDT(事件调度线程)来更新UI,如下所示:

      SwingUtilities.invokeLater(() -> {
        label = new JLabel(receive);
        label.setBounds(10,y,380,20);
        y = y+20;
        label.setHorizontalAlignment(SwingConstants.RIGHT);
        add(label);
        revalidate();
        repaint();
      });

在客户端和服务器端。希望这可以解决您的问题(虽然奇怪的是这不会导致异常)。

相关问题