【问题标题】:Sockets Multithreading Deadlock套接字多线程死锁
【发布时间】:2015-06-11 05:18:07
【问题描述】:

我有一个与this 类似的问题,但我知道当我要求阅读一行时,发件人应该发送一个行尾。

让我感到困惑的是,在调试中,它可以工作。可能是因为我在调试时跳过的顺序(直到现在我什至不知道这会有所作为),但我想更好地理解它。

我已经使用过线程,但不是很多。

这是我的服务器类:

import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

public class Server {

    protected static List<Game> games = new ArrayList<>();
    protected static List<ServerThread> players = new ArrayList<>();

    public static void main(String[] args) throws Exception {
        int serverPort = 8945;
        Server server = new Server();
        ServerSocket welcomeSocket = new ServerSocket(serverPort);

        while (true) {
            Socket connectionSocket = welcomeSocket.accept();
            ServerThread st = new ServerThread(server,connectionSocket);
            st.start();
            int gameId = 0;
            if(players.size()>0 && players.size()%2==0){
                gameId++;
                players.get(0).outToClient.write("START " + gameId
                        + " 123 456" +"\n");
                players.get(0).outToClient.flush();
                players.get(1).outToClient.write("START " + gameId
                        + " 456 123" +"\n");
                players.get(1).outToClient.flush();
            }
        }
    }
}

线程(基于this

import java.io.*;
import java.net.Socket;

public class ServerThread extends Thread {
    protected Server server;
    protected Socket socket;
    protected String playerName;   
    protected BufferedReader inFromClient;
    protected BufferedWriter outToClient;

    public ServerThread(Server server, Socket clientSocket) throws IOException {
        this.server = server;
        this.socket = clientSocket;
        this.inFromClient = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        this.outToClient = new BufferedWriter(new InputStreamReader(socket.getOutputStream()));
    }

    public void run() {
        while (true) {
            try {
                String line = inFromClient.readLine();
                if(line != null) {
                    String[] clientCommand = line.split(" ");
                    String commandType = clientCommand[0];
                    if (!commandType.equalsIgnoreCase("QUIT")) {
                        switch (commandType) {
                            case "JOIN":
                                playerName = clientCommand[1];
                                System.out.println(playerName + " joined");
                                Server.players.add(this);
                                break;
                            case "PLAY":
                                //nothing yet
                                break;
                            case "MSG":
                                //nothing yet
                                break;
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
                return;
            }
        }
    }

还有客户:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;

public class Client {

    private static int gameID;
    private static int order;
    private static String opponent;

    public static void main(String[] args) throws Exception {
        if (args.length != 1) {
            System.out.println("Usage: java Client <serverIp>");
            System.exit(1);
        }
        String serverIP = args[0];
        int serverPort = 8945;
        BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));
        Socket clientSocket = new Socket(serverIP, serverPort);
        BufferedWriter outToServer = new OutputStreamWriter(clientSocket.getOutputStream());
        BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

        String line = inFromUser.readLine();
        String[] commandSentence = line.split(" ");
        String userCommandType = commandSentence[0];
        while (!userCommandType.equals("/exit")){
            switch (userCommandType){
                case "/enter":
                    String nickname = commandSentence[1];
                    outToServer.write("JOIN "+ nickname + '\n');
                    outToServer.flush();
                    while (true){
                        String serverLine = inFromServer.readLine();
                        String[] serverCommand = serverLine.split(" ");
                        String serverCommandType = serverCommand[0];
                        if(serverCommandType.equalsIgnoreCase("START")){
                            gameID = Integer.parseInt(serverCommand[1]);
                            order = Integer.parseInt(serverCommand[2]);
                            opponent = serverCommand[3];
                            System.out.printf("%5s %5s %5s",gameID,order,opponent);
                            break;
                        }                            
                    }
                case "/play":
                    //nothing yet
                    break;
                case "/msg":
                    //nothing yet
                    break;
            }
        }
    }
}

它看起来像是在某个地方进入了死锁,并且由于某种原因,除非在调试中运行,否则永远不要在 Serverclass 上输入它向客户端发送数据

(顺便说一句,我使用 get(0)get(1) 仅用于测试目的)

编辑:好吧,我的愚蠢错误是当客户端向服务器发送数据时我忘记添加outToServer.flush();。但是我的主要问题仍然存在,当我通过对每个客户端键入“/enter ”来创建两个客户端时,当最后一个添加到列表中时,预计会在服务器上输入 if 语句。

【问题讨论】:

  • 您的程序描述含糊不清。 “死锁”是什么意思?实际发生了什么,或没有发生什么?哪个if 永远不会被输入,!st.isAlive() 一个?
  • 对不起。这取决于现在,当我开始这个问题时,我会说是的。但正如@EJP 所说,我已将DataOutputStream 更改为BufferedReader,现在它挂得更早了。我现在无法进行太多测试,但它看起来像是在 ServerThread 尝试 readLine() 时发生的。
  • 您为什么希望输入if?为什么线程不存在?
  • 抱歉,我之前没有while(true),这就是原因。
  • 您只需要在打开套接字时测试玩家的数量。但是您的测试是在套接字建立之后立即进行的,并且可能在客户端发送 JOIN 之前。

标签: java multithreading sockets


【解决方案1】:

一个问题是在您将命令发送到服务器的那一行的客户端代码中。您发送的字符串长度非常小,因此需要一个 outToServer.flush();正常工作

【讨论】:

  • 是的,我只是想通了。但这并不能阻止我的主要问题。它没有按预期输入if(players.size()&gt;0 &amp;&amp; players.size()%2==0)
  • 是的,我现在正在检查那条线,给我一些时间
  • ok 已解决,您必须打开 3 个客户端才能进入该循环,因为您在主线程中有 if 语句,因此它检查 list.size() 和列表.size() 稍后被服务器线程刷新,因此主线程只会在 3d 客户端之后进入 if
  • 每次获得一对用户时,我都需要创建一个游戏对象。我不能依赖第三个用户让其他人玩。
  • 是的,您的设计与您想做的不匹配。第一个问题是你试图在主线程中为客户端服务,而不是在负责指定客户端的线程中
【解决方案2】:

摆脱ready() 测试。它的正确用法很少。只需让以下读取块。

注意:不要将流与读者和作者混在一起。如果你使用BufferedInputStream 来阅读,你应该使用BufferedOutputStream 来写。

【讨论】:

  • 我添加了ready() 检查,因为至少在尝试阅读时挂起之前它会正确阅读。也许这是我没有注意到的输入和输出的相同问题。我从教授给我的模板中得到了那部分代码(输入和输出混合)......
  • 在从BufferedInputStreamBufferedOutputStream 中选择DataInputStreamDataOutputStream 之前,我应该考虑什么。我应该使用哪一对?
猜你喜欢
  • 2011-03-18
  • 1970-01-01
  • 2018-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多