现在想做一个类似于QQ群功能程序,做的过程遇到很多问题
Server类只需要实现接受每个client类的传出的信息,并且打印在自己的信息板上,
然后将接受的信息发送给每个client
也就是说,每个client能看到彼此发送的信息,功能类似于QQ群
client的功能一是打印自己输出的信息,二是接受Server传过来的信息,打印出来
初学网络编程,欢迎拍砖
下面是代码
Server 类package ex30;import javax.swing.*;import java.io.*;import java.io.IOException;
import java.net.*;
import java.util.*;public class Ex30_13Server extends JFrame{
private JTextArea jtaServer = new JTextArea();
private BufferedReader input;
private String sendMessage = "";
private ArrayList<Socket> socketArray = new ArrayList<Socket>();

public Ex30_13Server(){
jtaServer.setEditable(false);
add(new JScrollPane(jtaServer));
setTitle("MultiThreadServer");
setSize(700, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);

try{
ServerSocket serverSocket = new ServerSocket(8000);

while(true){
Socket socket = serverSocket.accept();
InetAddress inetAddress = socket.getInetAddress();
jtaServer.append(inetAddress.getHostName() + " connected " + new Date());
socketArray.add(socket);

MutiUser mu = new MutiUser(socket);
mu.start();
}
}
catch(Exception ex){
ex.printStackTrace();
}
}

//  Define the thread class for send message
class SendTask implements Runnable{
public void run(){
try{
while(true){
if(!sendMessage.isEmpty()){
for(Socket socket : socketArray){  // 将接受的信息输出到每个客户端上
PrintWriter outputToEachClient = new PrintWriter(socket.getOutputStream());
outputToEachClient.println(sendMessage);
}
sendMessage = "";
}
}
}
catch(Exception ex){
ex.printStackTrace();
}

}
}


// Define the thread class for receive message
class ReceiveTask implements Runnable{
public void run(){
try{
while(true){
String receiveMessage = input.readLine();
if(!receiveMessage.isEmpty()){
jtaServer.append(receiveMessage + "\n");
sendMessage = receiveMessage;
}

}
}
catch(IOException ex){
ex.printStackTrace();
}
}
}

class MutiUser extends Thread{
private Socket server;

public MutiUser(Socket server){
this.server = server;
}

public void run(){
try{
input = new BufferedReader(new InputStreamReader(server.getInputStream()));
new Thread(new SendTask()).start();
new Thread(new ReceiveTask()).start();
}
catch(Exception ex){
ex.printStackTrace();
}
}
}

public static void main(String[] args) {
// TODO 自动生成方法存根
new Ex30_13Server();
}}
client类package ex30;import javax.swing.*;import ex30.Ex30_12Client.ReceiveTask;
import ex30.Ex30_12Client.SendTask;import java.io.*;import java.awt.*;
import java.awt.event.*;
import java.net.*;public class Ex30_13Client extends JFrame{
private JLabel jlblName = new JLabel("Name");
private JLabel jlblText = new JLabel("Enter text");
private JTextField jtfName = new JTextField();
private JTextField jtfText = new JTextField();
private JTextArea jtaClient = new JTextArea();
private PrintWriter output;
private BufferedReader input;
private String sendMessage = "";

public Ex30_13Client(){
JPanel panel1 = new JPanel(new GridLayout(2, 1));
panel1.add(jlblName);
panel1.add(jlblText);

JPanel panel2 = new JPanel(new GridLayout(2, 1));
panel2.add(jtfName);
panel2.add(jtfText);

JPanel panel = new JPanel(new BorderLayout());
panel.add(panel1, BorderLayout.WEST);
panel.add(panel2, BorderLayout.CENTER);

setLayout(new BorderLayout());
add(panel, BorderLayout.NORTH);
add(jtaClient, BorderLayout.CENTER);
jtaClient.setEditable(false);

setTitle("Ex30_13Client");;
setSize(500, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);


jtfText.addKeyListener(new KeyAdapter(){
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_ENTER){
String text = jtfText.getText();

if(!text.isEmpty()){
sendMessage = jtfName.getText() + ":" + text;
output.println(sendMessage);
output.flush();
System.out.println(sendMessage);
jtfText.setText("");  
}
}
}
});

try{
Socket socket = new Socket("localhost", 8000);
output = new PrintWriter(socket.getOutputStream());
input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
new Thread(new SendTask()).start();
new Thread(new ReceiveTask()).start();
}
catch (Exception ex){
ex.printStackTrace();
}

}

class SendTask implements Runnable{
public void run(){
try{
while(true){
if(!sendMessage.isEmpty()){
jtaClient.append(sendMessage + "\n");
sendMessage = "";
}
}
}
catch(Exception ex){
ex.printStackTrace();
}
}
}

class ReceiveTask implements Runnable{
public void run(){
try{
while(true){
String receiveMessage = input.readLine();
jtaClient.append(receiveMessage + "\n");
}
}
catch(Exception ex){
ex.printStackTrace();
}
}
}



public static void main(String[] args) {
// TODO 自动生成方法存根
new Ex30_13Client();
}}

解决方案 »

  1.   

    问题很多,主要是多线程数据同步的问题,建议你多看看这方面的书,学习使用java.util.concurrent包里的各种工具类。尽量不要把代码都写在构造器里面,这是很不好的习惯。
      

  2.   

    client类里有时候发出的信息,Server接不到,其他的client就更接不到了
      

  3.   

    server 类改一下,关键是整体设计不太好package ex40;import javax.swing.*;import java.io.*;import java.io.IOException;
    import java.net.*;
    import java.util.*;public class Ex30_13Server extends JFrame {
    private JTextArea jtaServer = new JTextArea();
    private String sendMessage = "";
    private ArrayList<Socket> socketArray = new ArrayList<Socket>(); public Ex30_13Server() {
    jtaServer.setEditable(false);
    add(new JScrollPane(jtaServer));
    setTitle("MultiThreadServer");
    setSize(700, 300);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setVisible(true); try {
    ServerSocket serverSocket = new ServerSocket(8000); while (true) {
    Socket socket = serverSocket.accept();
    InetAddress inetAddress = socket.getInetAddress();
    jtaServer.append(inetAddress.getHostName() + " connected "
    + new Date());
    socketArray.add(socket); MutiUser mu = new MutiUser(socket);
    mu.start();
    }
    } catch (Exception ex) {
    ex.printStackTrace();
    }
    } // Define the thread class for send message
    class SendTask implements Runnable {
    private MutiUser mu; public SendTask(MutiUser mu) {
    this.mu=mu;
    } public void run() {
    try {
    while (true) {
    if (!sendMessage.isEmpty()) {
    for (Socket socket : socketArray) { // 将接受的信息输出到每个客户端上
    PrintWriter outputToEachClient = new PrintWriter(
    socket.getOutputStream());
    outputToEachClient.println(sendMessage);
    }
    sendMessage = "";
    }
    }
    } catch (Exception ex) {
    ex.printStackTrace();
    } }
    } // Define the thread class for receive message
    class ReceiveTask implements Runnable {
    private MutiUser mu;

    public ReceiveTask(MutiUser mu)
    {
    this.mu=mu;
    }
    public void run() {
    try {
    while (true) {
    String receiveMessage = mu.input.readLine();
    if (!receiveMessage.isEmpty()) {
    jtaServer.append(receiveMessage + "\n");
    sendMessage = receiveMessage;
    } }
    } catch (IOException ex) {
    ex.printStackTrace();
    }
    }
    } class MutiUser extends Thread {
    private Socket server;
    private BufferedReader input; public MutiUser(Socket server) {
    this.server = server;
    } public void run() {
    try {
    input = new BufferedReader(new InputStreamReader(
    server.getInputStream()));
    new Thread(new SendTask(this)).start();
    new Thread(new ReceiveTask(this)).start();
    } catch (Exception ex) {
    ex.printStackTrace();
    }
    }
    } public static void main(String[] args) {
    // TODO 自动生成方法存根
    new Ex30_13Server();
    }}
      

  4.   

    太棒了,现在client传出的信息server可以都接受到
    但是还有一个问题,就是server接受的信息,
    不知道是没有发送给client,还是client没接收到
    我原本是想用每一个客户端创建的Socket,添加到socketArray,
    然后接收到后通过每个socket 传给各个client
    就差这一步了,我已经想了很久了,恳求楼上再看看是怎么回事
      

  5.   

    闲来无事帮你改了改,服务器端改得多点,客户端基本没动,能完成你要的功能了package ex30;import javax.swing.*;
    import java.io.*;import java.io.IOException;
    import java.net.*;
    import java.util.*;
    import java.util.concurrent.ConcurrentLinkedQueue;public class Ex30_13Server extends JFrame implements Runnable{
    private JTextArea jtaServer = new JTextArea();
        private BufferedReader input;
        private String sendMessage = "";
        private ConcurrentLinkedQueue<String> messageQueue = null;
        private ArrayList<Socket> socketArray = new ArrayList<Socket>();
        
        public Ex30_13Server(){
            jtaServer.setEditable(false);
            add(new JScrollPane(jtaServer));
            setTitle("MultiThreadServer");
            setSize(700, 300);
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setVisible(true);
            this.messageQueue = new ConcurrentLinkedQueue<String>();
            new Thread(this).start();
        }
        
        @Override
    public void run() {
         ServerSocket serverSocket = null;
         try{
         serverSocket = new ServerSocket(8000);
         new Thread(new broadcaster()).start();
         while(true){
         Socket socket = serverSocket.accept();
         InetAddress inetAddress = socket.getInetAddress();
         synchronized (socketArray){
                     socketArray.add(socket);
                    }
         new Thread( new UserInput(socket)).start();
         synchronized (jtaServer) {
         jtaServer.append(inetAddress.getHostName() + " connected " + new Date()+ "\n");
         }
         }
        
         } catch(Exception ex){
                ex.printStackTrace();
            } finally {
             try {
    serverSocket.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
            }
        }
        
        class broadcaster implements Runnable{ @Override
    public void run() {
    while (true){
    if (!messageQueue.isEmpty()){
    synchronized (socketArray){
    try {
    String message = messageQueue.poll();
    for(Socket socket : socketArray){  // 将接受的信息输出到每个客户端上
    PrintWriter outputToEachClient = new PrintWriter(socket.getOutputStream());
    outputToEachClient.println(message);
    outputToEachClient.flush();
    }
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }
    }
    }
        }
        
        class UserInput implements Runnable {
         private Socket socket;    
            
            public UserInput(Socket socket){
                this.socket = socket;            
            }
        
    @Override
    public void run() {
    try {
    BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    String inputLine = null;
    while (true){
    while ((inputLine = in.readLine()) != null) {
    messageQueue.add(inputLine);
    jtaServer.append(inputLine+"\n");
    }
    }
    } catch (Exception e) {
    //e.printStackTrace();
    } finally {
    try {
    socket.close();
    synchronized (socketArray){
                     socketArray.remove(socket);
                    }
    } catch (IOException e1) {
    System.out.println("Can not close socket");
    }
    }
    }
        }
        
        public static void main(String[] args) {
            // TODO 自动生成方法存根
            new Ex30_13Server();
        }
    }
    package ex30;import javax.swing.*;import java.io.*;import java.awt.*;
    import java.awt.event.*;
    import java.net.*;public class Ex30_13Client extends JFrame{
        private JLabel jlblName = new JLabel("Name");
        private JLabel jlblText = new JLabel("Enter text");
        private JTextField jtfName = new JTextField();
        private JTextField jtfText = new JTextField();
        private JTextArea jtaClient = new JTextArea();
        private PrintWriter output;
        private BufferedReader input;
        private String sendMessage = "";
        
        public Ex30_13Client(){
            JPanel panel1 = new JPanel(new GridLayout(2, 1));
            panel1.add(jlblName);
            panel1.add(jlblText);
            
            JPanel panel2 = new JPanel(new GridLayout(2, 1));
            panel2.add(jtfName);
            panel2.add(jtfText);
            
            JPanel panel = new JPanel(new BorderLayout());
            panel.add(panel1, BorderLayout.WEST);
            panel.add(panel2, BorderLayout.CENTER);
            
            setLayout(new BorderLayout());
            add(panel, BorderLayout.NORTH);
            add(jtaClient, BorderLayout.CENTER);
            jtaClient.setEditable(false);
            
            setTitle("Ex30_13Client");;
            setSize(500, 300);
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setLocationRelativeTo(null);
            setVisible(true);
            
            
            jtfText.addKeyListener(new KeyAdapter(){
                public void keyPressed(KeyEvent e){
                    if(e.getKeyCode() == KeyEvent.VK_ENTER){
                        String text = jtfText.getText();
                        
                        if(!text.isEmpty()){
                            sendMessage = jtfName.getText() + ":" + text;
                            output.println(sendMessage);
                            output.flush();
                            System.out.println(sendMessage);
                            jtfText.setText("");  
                        }
                    }
                }
            });
            
            try{
                Socket socket = new Socket("localhost", 8000);
                output = new PrintWriter(socket.getOutputStream());
                input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                new Thread(new ReceiveTask()).start();
            }
            catch (Exception ex){
                ex.printStackTrace();
            }
        }
        
        class ReceiveTask implements Runnable{
            public void run(){
                try{
                 String inputLine = null;
    while (true){
    while ((inputLine = input.readLine()) != null) {
    jtaClient.append(inputLine+"\n");
    }
    }
                }
                catch(Exception ex){
                    ex.printStackTrace();
                }
            }
        }
        
        public static void main(String[] args) {
            // TODO 自动生成方法存根
            new Ex30_13Client();
        }}
      

  6.   

    闲来无事帮你写了写,服务器端改得多了点,客户端基本没动,能完成你要的功能
    服务器端
    package ex30;import javax.swing.*;
    import java.io.*;import java.io.IOException;
    import java.net.*;
    import java.util.*;
    import java.util.concurrent.ConcurrentLinkedQueue;public class Ex30_13Server extends JFrame implements Runnable{
    private JTextArea jtaServer = new JTextArea();
        private BufferedReader input;
        private String sendMessage = "";
        private ConcurrentLinkedQueue<String> messageQueue = null;
        private ArrayList<Socket> socketArray = new ArrayList<Socket>();
        
        public Ex30_13Server(){
            jtaServer.setEditable(false);
            add(new JScrollPane(jtaServer));
            setTitle("MultiThreadServer");
            setSize(700, 300);
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setVisible(true);
            this.messageQueue = new ConcurrentLinkedQueue<String>();
            new Thread(this).start();
        }
        
        @Override
    public void run() {
         ServerSocket serverSocket = null;
         try{
         serverSocket = new ServerSocket(8000);
         new Thread(new broadcaster()).start();
         while(true){
         Socket socket = serverSocket.accept();
         InetAddress inetAddress = socket.getInetAddress();
         synchronized (socketArray){
                     socketArray.add(socket);
                    }
         new Thread( new UserInput(socket)).start();
         synchronized (jtaServer) {
         jtaServer.append(inetAddress.getHostName() + " connected " + new Date()+ "\n");
         }
         }
        
         } catch(Exception ex){
                ex.printStackTrace();
            } finally {
             try {
    serverSocket.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
            }
        }
        
        class broadcaster implements Runnable{ @Override
    public void run() {
    while (true){
    if (!messageQueue.isEmpty()){
    synchronized (socketArray){
    try {
    String message = messageQueue.poll();
    for(Socket socket : socketArray){  // 将接受的信息输出到每个客户端上
    PrintWriter outputToEachClient = new PrintWriter(socket.getOutputStream());
    outputToEachClient.println(message);
    outputToEachClient.flush();
    }
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }
    }
    }
        }
        
        class UserInput implements Runnable {
         private Socket socket;    
            
            public UserInput(Socket socket){
                this.socket = socket;            
            }
        
    @Override
    public void run() {
    try {
    BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    String inputLine = null;
    while (true){
    while ((inputLine = in.readLine()) != null) {
    messageQueue.add(inputLine);
    jtaServer.append(inputLine+"\n");
    }
    }
    } catch (Exception e) {
    //e.printStackTrace();
    } finally {
    try {
    socket.close();
    synchronized (socketArray){
                     socketArray.remove(socket);
                    }
    } catch (IOException e1) {
    System.out.println("Can not close socket");
    }
    }
    }
        }
        
        public static void main(String[] args) {
            // TODO 自动生成方法存根
            new Ex30_13Server();
        }
    }客户端package ex30;import javax.swing.*;import java.io.*;import java.awt.*;
    import java.awt.event.*;
    import java.net.*;public class Ex30_13Client extends JFrame{
        private JLabel jlblName = new JLabel("Name");
        private JLabel jlblText = new JLabel("Enter text");
        private JTextField jtfName = new JTextField();
        private JTextField jtfText = new JTextField();
        private JTextArea jtaClient = new JTextArea();
        private PrintWriter output;
        private BufferedReader input;
        private String sendMessage = "";
        
        public Ex30_13Client(){
            JPanel panel1 = new JPanel(new GridLayout(2, 1));
            panel1.add(jlblName);
            panel1.add(jlblText);
            
            JPanel panel2 = new JPanel(new GridLayout(2, 1));
            panel2.add(jtfName);
            panel2.add(jtfText);
            
            JPanel panel = new JPanel(new BorderLayout());
            panel.add(panel1, BorderLayout.WEST);
            panel.add(panel2, BorderLayout.CENTER);
            
            setLayout(new BorderLayout());
            add(panel, BorderLayout.NORTH);
            add(jtaClient, BorderLayout.CENTER);
            jtaClient.setEditable(false);
            
            setTitle("Ex30_13Client");;
            setSize(500, 300);
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setLocationRelativeTo(null);
            setVisible(true);
            
            
            jtfText.addKeyListener(new KeyAdapter(){
                public void keyPressed(KeyEvent e){
                    if(e.getKeyCode() == KeyEvent.VK_ENTER){
                        String text = jtfText.getText();
                        
                        if(!text.isEmpty()){
                            sendMessage = jtfName.getText() + ":" + text;
                            output.println(sendMessage);
                            output.flush();
                            System.out.println(sendMessage);
                            jtfText.setText("");  
                        }
                    }
                }
            });
            
            try{
                Socket socket = new Socket("localhost", 8000);
                output = new PrintWriter(socket.getOutputStream());
                input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                new Thread(new ReceiveTask()).start();
            }
            catch (Exception ex){
                ex.printStackTrace();
            }
        }
        
        class ReceiveTask implements Runnable{
            public void run(){
                try{
                 String inputLine = null;
    while (true){
    while ((inputLine = input.readLine()) != null) {
    jtaClient.append(inputLine+"\n");
    }
    }
                }
                catch(Exception ex){
                    ex.printStackTrace();
                }
            }
        }
        
        public static void main(String[] args) {
            // TODO 自动生成方法存根
            new Ex30_13Client();
        }}
      

  7.   

    有点不理解为什么Server类也要实现Runnable接口