当前位置: 首页 > 知识库问答 >
问题:

套接字多线程死锁

林元明
2023-03-14

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

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

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

这是我的服务器类:

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();
            }
        }
    }
}

线程(基于此)

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

它似乎在某个地方进入了死锁,出于某种原因,除非在调试中运行,否则永远不要在向客户端发送数据的服务器类上输入该死锁

(顺便说一句,我使用的是get(0)和get(1)之类的工具,仅用于测试目的)

编辑:好吧,我愚蠢的错误是我忘记在客户端向服务器发送数据时添加outToServer.flush();。但是我的主要问题仍然存在,当我通过键入"/Enter创建两个客户端时

共有2个答案

金令
2023-03-14

摆脱测试。它的正确用法很少。只需让下面的read阻塞即可。

注意:不要将流与读者和作者混为一谈。如果您正在使用BufferedInputStream进行读取,那么您应该使用BufferedOutputStream进行写入。

宇文元明
2023-03-14

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

 类似资料:
  • 这是我的客户端和服务器的代码。 class Client1{Client1(int no){try{String message;message=“Hello this is client”+no;byte[]b=message.getBytes();DatagramPacket dp=new DatagramPacket(b,b length,inetAddress.getLocalHost()

  • 问题内容: 如果我有多个Java线程同时写入同一Socket实例,这会影响从同一套接字读取的对象的完整性吗?即,对象的内容是否会被弄乱等等。对象的顺序可以是随机的。 问题答案: 通常,没有任何保证。一点点不同的对象很可能最终会在电线上交错,使结果难以辨认。 因此,您需要提供外部同步。 有趣的是,即使在OS级别进行单个套接字写入也不一定是原子操作。有关进一步的讨论,请参见注意sendmsg()系列函

  • 我是python套接字编程的初学者,正在尝试编写一个与联网家庭自动化设备(GlobalCache GC100)接口的库 我既需要通过TCP不断监听来自该硬件的传感器状态变化事件,也需要能够在用户发起的时间发送set_state命令(trip relays),而没有明显的延迟。 我有一个循环,它执行来拾取状态更改事件。这通常会超时()并继续到下一个循环迭代,直到设备推送状态更改数据。 我是想做套接字

  • 问题内容: 我正在尝试在C中创建一个多线程服务器- 客户端文件传输系统。有些客户端将发送或列出或做其他选择(在交换机的情况下,您可以看到),而服务器则存储文件并提供大量服务客户。 就我所知,多线程意识形态确实很困难。它需要太多的经验而不是知识。我已经在该项目上工作了一个多星期,但我一直无法解决这些问题。 有4个选择:第一个是在其目录中列出客户端的本地文件,第二个是在客户端和服务器之间传输的列表文件

  • 我有一个socket客户端应用程序,在应用程序启动期间,会创建socket(与服务器建立连接),并启动两个并行运行的线程。 Thread-1:使用read方法连续读取套接字(块,直到收到数据) Thread-2:连续写入数据。 在写入套接字时,如果线程2接收到IO异常,那么它会丢弃现有的套接字并创建新的套接字并开始通信。由于线程2丢弃套接字,线程1接收空指针异常。我们有什么应对策略吗

  • 我是Java和JavaFX的新手,所以请原谅我的新手问题。在过去的几天里,我一直在寻找我正在努力做的事情的例子,但是没有找到任何答案。下面是我正在尝试做的:我试图创建一个简单的javafx GUI客户端套接字应用程序,使用场景生成器连接到服务器并发送/接收数据。很简单,但是当我试图在JavaFX中实现它时,我的图形用户界面冻结了。我研究发现,原因是套接字通信占用了所有的时间,javafx GUI无