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

多线程客户端/服务器应用程序java问题,java,multithreading,sockets,client,chat,Java,Multithreading,Sockets,Client,Chat,这是我的第一篇帖子,如果我做错了,请纠正我 我正在尝试制作一个多线程的客户机/服务器应用程序。我可以在没有线程的情况下创建一个基本的1对1客户机/服务器应用程序,但是我希望每个客户机单独与服务器对话,并且每个客户机只在控制台中接收属于特定客户机的消息。这就是我不能让它工作的地方 我在网上看了一些教程,并尝试在Eclipse中进行调试,但没有任何运气。 我希望应用程序执行的操作: 如果我运行服务器和2个客户机,我希望能够在客户机上编写消息,并使服务器返回消息和消息编号,而不跳过编号 客户1: 消息

这是我的第一篇帖子,如果我做错了,请纠正我

我正在尝试制作一个多线程的客户机/服务器应用程序。我可以在没有线程的情况下创建一个基本的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();
}
}
线程服务器代码:

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

}
  }

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

您还应该遵循注释中的建议并移动套接字创建

-编辑-

对于
ThreadServer
,同样如此,不要在循环中执行套接字初始化。只是阅读

稍后您可能还会发现,您需要为客户机添加一个额外的线程。就现在这样 似乎每个客户端只能在单击“执行的操作”按钮时接收消息, 这可能不是你想要的。这将暴露一些同步问题 这是您必须处理的,但大多数gui库实际上可能会在这方面帮助您。 我很久没有处理swing了

-重新编辑- 此外,请阅读异常处理。你应该决定你要去哪里 捕获IO异常,而不是随机嵌套try/catch和声明方法
就像扔它们一样。

让我试着解决它

  • 只创建一个
    ServerSocket
    。在循环时从
    移动到行下方。将它放在
    之前,而
    循环

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

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

    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++;
}

你不应该做
listener=newserversocket(9090)在循环中,因为端口周围的第二次将很忙,创建将失败。只需在循环之前创建一次服务器套接字,并在循环中多次调用同一服务器套接字上的accept。一个建议是,将您在server和ThreadServer类的构造函数中编写的代码添加到各自的运行方法中。非常感谢。现在它起作用了。不过,我很高兴我很亲近。:)感谢您的输入,我的异常处理还不是很好,所以您指出这一点很好。到目前为止,我们只编写了7个月的代码。