多线程客户端/服务器应用程序java问题

时间:2014-04-16 18:54:50

标签: java multithreading sockets client chat

这是我的第一篇文章,如果我做错了,请纠正我。

我正在尝试创建一个多线程客户端/服务器应用程序。我没有问题在没有线程的情况下制作一个基本的1对1客户端/服务器应用程序,但我希望每个客户端单独与服务器通信,每个客户端只接收属于控制台中特定客户端的消息。这是我无法工作的地方。

我已经在线查看了一些教程,我试着在Eclipse中调试而没有任何运气。 我希望应用程序做什么:

如果我运行服务器和2个客户端,我希望能够在客户端上编写消息,并使服务器返回消息和消息号而不跳过数字。

客户1:

消息号:0。你说:你好!

消息号:1。你说:什么了!

客户2:

消息号:0。你说:嘿服务器!

消息号:1。你说:你现在在做什么?

它与我运行的第一个客户端一起工作并完美地增加了messagenumber,但是当我创建第二个时它会冻结,所以我想我的问题是使用套接字声明或我的线程方式。 (也许某个地方缺少socket.close()?)

我知道应用程序存在一些其他缺陷,但请记住,这只是一个用于处理线程的学校作业。

如果有人愿意提供帮助,请提前致谢。 :)

服务器代码:

public class Server extends Thread 
{   
  DataInputStream in;
  DataOutputStream out;
  ServerSocket listener;

public Server() throws IOException
{      
    try 
    {
        while (true) 
        {
            listener = new ServerSocket(9090);
            Socket socket = listener.accept(); 
            System.out.println("Test");
            ThreadServer ts = new ThreadServer(socket);
            Thread t1 = new Thread(ts);
            t1.start();   
        }
    }
    finally 
    {
        listener.close();
    }   
}

public static void main(String[] args) throws IOException 
{
    new Server();
}
}

客户代码:

public class Client extends JFrame 
 {      
   DataOutputStream dos;
   BufferedReader input;
   String answer = null;
   String textString;
   Socket s = new Socket("localhost", 9090);

public Client() throws IOException
{
    JButton btn = new JButton("run");
    final JTextField txf = new JTextField(10);
    btn.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent arg0) {             
            try 
            {   
                dos = new DataOutputStream(s.getOutputStream());
                textString = txf.getText();
                dos.writeUTF(textString);
                dos.flush();        
                input = new BufferedReader(new InputStreamReader(s.getInputStream()));
                answer = input.readLine();                      
            } 
            catch (Exception e1) 
            {
                e1.printStackTrace();
            }           
                System.out.println(answer); 
            }       
    });
    setLayout(new GridLayout(2,2));
    add(btn);
    add(txf);
    setVisible(true);
    pack();
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

}

public static void main(String[] args) throws IOException 
{
    new Client();
}
}

ThreadServer代码:

public class ThreadServer implements Runnable
{
  DataInputStream in;
  DataOutputStream out;

public ThreadServer (Socket socket) throws IOException
{       
    int i = 0;  

    try 
    {
        while (true) 
        {            
            in = new DataInputStream(socket.getInputStream());
            out = new DataOutputStream(socket.getOutputStream());

            try 
            {
                String message = in.readUTF();          
                PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
                out.println("Message no: " + i + ". You said: " + message);                  
                out.println("Message no: " + i);
            }
            catch(Exception e) 
            {
                e.printStackTrace();
            }
            i++;
        }
    }
    finally 
    {
        socket.close();
    }
}

@Override
public void run() {
    // TODO Auto-generated method stub

}
  }

2 个答案:

答案 0 :(得分:3)

让我试着解决它。

  • 只创建一个ServerSocket。从while循环移到第一行以下。把它放在while循环之前。

    listener = new ServerSocket(9090);
    
  • ThreadServer的构造函数的代码移至run()方法,因为它实现了Runnable但不像Runnable那样行事类。

    public ThreadServer(Socket socket) throws IOException {
        this.socket=socket;
    }
    
    @Override
    public void run() {
       ...
       //code from constructor
    }
    
  • 在Server类中,您正在向客户端写两行,但客户端只读一行。删除额外的行,如下所示

    out.println("Message no: " + i + ". You said: " + message);
    //out.println("Message no: " + i);
    

最后一个建议:

在致电readUTF()之前,请务必检查输入,如下所示:

if (in.available() > 0) {
    try {
        String message = in.readUTF();
        PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
        out.println("Message no: " + i + ". You said: " + message);
        //out.println("Message no: " + i);
    } catch (Exception e) {
        e.printStackTrace();
    }
    i++;
}

答案 1 :(得分:0)

您的ThreadServer在构造函数中无限循环,而不是run方法。 这真是太糟了。 run方法是你应该放置代码的地方。

您还应该遵循评论中的建议并移动套接字创建。

-edit -

对于ThreadServer也是如此,不要在循环中执行套接字init。只是阅读。

稍后您可能还会发现客户端需要额外的线程。就像现在一样 似乎每个客户端只能在单击动作执行按钮时接收消息, 这可能不是你想要的。这将暴露一些同步问题 你将不得不处理,但大多数你gui库可能实际上帮助你那里。 我处理挥杆已经很久了。

- 再次编辑 - 另外,阅读异常处理。你应该决定你想要的地方 捕获IO异常,而不是随机嵌套try / catch和声明方法 抛弃它们。