多线程中的套接字“死锁”Java

时间:2013-03-19 13:29:20

标签: java multithreading sockets deadlock

我试图在同一个进程上启动服务器和客户端线程,但似乎服务器线程阻塞了客户端线程(反之亦然)。我不允许在这些线程之间使用任何全局变量(如信号量或互斥量,因为客户端和服务器线程是由我无法访问的上层类启动的。)

我发现了一个类似的问题here,但它仍然使用两个不同的过程(两个主要功能)。

以下是我的代码示例

服务器代码:

public class MyServer implements Runnable{

    ServerSocket server;
    Socket client;
    PrintWriter out;
    BufferedReader in;

    public MyServer() throws IOException{
        server = new ServerSocket(15243, 0, InetAddress.getByName("localhost"));
    }

    @Override
    public void run() {
        while(true){
            try {

                ArrayList<String> toSend = new ArrayList<String>();

                System.out.println("I'll wait for the client");
                client = server.accept();
                out = new PrintWriter(client.getOutputStream(), true);
                in = new BufferedReader(new InputStreamReader(client.getInputStream()));

                String inputLine;
                while((inputLine = in.readLine()) != null){
                    toSend.add("answering : "+inputLine);
                }

                for(String resp : toSend){
                    out.println(resp);
                }

                client.close();
                out.close();
                in.close();

            } catch (IOException ex) {
            }

        }
    }
}

客户端代码:

public class MyClient implements Runnable{

    Socket socket;
    PrintWriter out;
    BufferedReader in;

    public MyClient(){
    }

    @Override
    public void run() {
        int nbrTry = 0;
        while(true){
            try {
                System.out.println("try number "+nbrTry);
                socket = new Socket(InetAddress.getByName("localhost"), 15243);

                out = new PrintWriter(socket.getOutputStream(), true);
                in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

                out.println("Hello "+nbrTry+" !! ");

                String inputLine;
                while((inputLine = in.readLine()) != null){
                    System.out.println(inputLine);
                }
                nbrTry++;
            } catch (UnknownHostException ex) {
            } catch (IOException ex) {
            }
        }
    }
}

所谓的上流社会推出了这些主题:

public class TestIt {

    public static void main(String[] argv) throws IOException{
        MyServer server = new MyServer();
        MyClient client = new MyClient();
        (new Thread(server)).start();
        (new Thread(client)).start();
    }
}

它给了我输出:

I'll wait for the client
Try number 0

它卡在这里。我应该怎么做以保持服务器和客户端代码运行? 谢谢。

2 个答案:

答案 0 :(得分:1)

我愿意接受你的问题,但基本上你需要仔细考虑你的逻辑。

MyServer.java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class MyServer implements Runnable {

  ServerSocket server;

  public MyServer() throws IOException {
    server = new ServerSocket(15243, 0, InetAddress.getByName("localhost"));
  }

  @Override
  public void run() {
    while (true) {
      try {
        // Get a client.
        Socket client = server.accept();

        // Write to client to tell him you are waiting.
        PrintWriter out = new PrintWriter(client.getOutputStream(), true);
        out.println("[Server] I'll wait for the client");
        // Let user know something is happening.
        System.out.println("[Server] I'll wait for the client");

        // Read from client.
        BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
        String inputLine = in.readLine();

        // Write answer back to client.
        out.println("[Server] Answering : " + inputLine);

        // Let user know what it sent to client.
        System.out.println("[Server] Answering : " + inputLine);

        in.close();
        out.close();
        client.close();
      } catch (Exception e) {

      }
    }
  }
}

MyClient.java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

public class MyClient implements Runnable {

  Socket socket;
  PrintWriter out;
  BufferedReader in;

  public MyClient() throws UnknownHostException, IOException {
  }

  @Override
  public void run() {
    int nbrTry = 0;
    while (true) {
      try {
        // Get a socket
        socket = new Socket(InetAddress.getByName("localhost"), 15243);

        // Wait till you can read from socket.
        in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String inputLine = in.readLine();
        //inputLine contains the text '[Server] I'll wait for the client'. means that server is waiting for us and we should respond.

        // Write to socket
        out = new PrintWriter(socket.getOutputStream(), true);
        out.println("[Client] Hello " + nbrTry + " !! ");

        // Let user know you wrote to socket
        System.out.println("[Client] Hello " + nbrTry++ + " !! ");

      } catch (UnknownHostException ex) {
      } catch (IOException ex) {
      }
    }
  }
}

TestIt.java

import java.io.IOException;

public class TestIt {

  public static void main(String[] argv) throws IOException {
    MyServer server = new MyServer();
    MyClient client = new MyClient();
    (new Thread(server)).start();
    (new Thread(client)).start();
  }
}

答案 1 :(得分:1)

您的客户端发送一个字符串,然后读取直到该流耗尽:

                while((inputLine = in.readLine()) != null){

BufferedReader.readLine()只在流的末尾返回null,我记得。在流上,它将阻塞,直到输入可用

您的服务器会在流用尽之前收到,然后发回其响应。

发送一行后,您现在拥有:

  • 您的客户等待回复。
  • 您的服务器仍在等待来自客户端的更多数据。但它直到客户端流结束时才会发送任何内容(由于客户端正在等待您的响应,因此不会发生这种情况)。