向客户端发送消息TCP连接因nullpointexception而失败

时间:2016-10-14 07:10:52

标签: java multithreading sockets tcp

大家好:)抱歉这个很长的问题,但这需要一些解释。

我获得了一项任务,我必须将一个非常简单的游戏变成一个2人多人游戏。我们必须制作这个游戏的原因是为了更多地了解线程和并发性。我从未使用过并发和多线程。

我的想法是创建一个TCP服务器,就像我在GameServer.java中所做的那样,我为每个玩家创建一个新的ServiceObject。我为每个ServiceObject创建一个线程,我将从客户端接收,处理和发送命令。

Gameserver.java

package server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

public class GameServer {
    public static void main(String[] args) throws IOException {
        ServerSocket server = new ServerSocket(6789);
        System.out.println("Waiting for clients to connect . . . ");

        Socket s1 = server.accept();
        System.out.println("Clients connected.");
        PlayerService servicep1 = new PlayerService(s1);
        Thread t1 = new Thread(servicep1);
        Socket s2 = server.accept();
        System.out.println("Clients connected.");
        PlayerService servicep2 = new PlayerService(s2);
        Thread t2 = new Thread(servicep2);
        t1.start();
        t2.start();
        servicep1.sendDataToClient("ready");
        servicep2.sendDataToClient("ready");
    }
}

PlayerService.java

package server;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.concurrent.LinkedBlockingQueue;

import game2016.Player;

public class PlayerService extends Thread {
    private Socket s;
    private PlayerService opponent;
    private Scanner in;
    private PrintWriter out;


    public PlayerService(Socket aSocket) {
        this.s = aSocket;
    }

    public void setOpponent(PlayerService opponent) {
        this.opponent = opponent;
    }

    public void run() {
        try {
            in = new Scanner(s.getInputStream());
            out = new PrintWriter(s.getOutputStream());
            try {
                doService();
            } finally {
//              s.close();
            }
        } catch (IOException exception) {
            exception.printStackTrace();
        }
    }

    public void doService() throws IOException {
        while (true) {
            if (!in.hasNext()) {
                return;
            }
            String command = in.next();
            if (command.equals("QUIT")) {
                return;
            } else
                recieveFromClient(command);
        }
    }

    public void recieveFromClient(String command) throws IOException {
        System.out.println(command);
        if(command.equals("player")) {
            String newPlayerName = in.next();
            int xPos = in.nextInt();
            int yPos = in.nextInt();
            String direction = in.next();
//          sendDataToOpponent("addOpponent " + newPlayerName + " " + xPos + " " +  yPos + " " + direction);
        } 
    }

    public void sendDataToClient(String response) {
        out.write(response + "\n");
        out.flush();
    }

    public void sendDataToOpponent(String response) {
        opponent.sendDataToClient(response);
    }

    }

要将数据从一个客户端发送到另一个客户端,我有一个对对手服务层的引用,因为我可以调用sendDataToOpponent()方法向他发送数据,如果服务器必须通信我可以从中调用sendDataToClient()服务器

我的问题是我想推迟打开我的客户GUI,两个客户都已连接。

Main.java(客户端) - 遗漏了GUI代码

private static Socket s;
private static InputStream instream;
private static OutputStream outstream;
private static Scanner in;
private static PrintWriter out;
private static boolean isOpponentConnected;

public static void main(String[] args) throws Exception {
    openConnection();
    reciever();
    waitOpponentConected();
    launch(args);
}

public static void waitOpponentConected() throws Exception {
    while(!isOpponentConnected) {
        System.out.println("Waiting for opponent");
        Thread.sleep(2000);
    }
    System.out.println("Opponent is ready now");
}

public static void openConnection() throws IOException {
    s = new Socket("localhost", 6789);
    System.out.println("Connection established");

    instream = s.getInputStream();
    outstream = s.getOutputStream();
    in = new Scanner(instream);
    out = new PrintWriter(outstream);
}

public static void responseFromServer() throws IOException {
     try {
         while(in.hasNext()) {
                String response = in.next();
                if(response.equals("ready")) {
                    isOpponentConnected = true;
                    System.out.println("Ready");
                } 
         }
        } catch (Exception e) {
        }
 }

public static void reciever() {
    Task<Void> task = new Task<Void>() {

        @Override
        protected Void call() throws Exception {
            while(true) {
                responseFromServer();
            }
        }

    };
    new Thread(task).start();
}

public static void sendCommandToServer(String command) throws IOException {
    out.print(command + "\n");
    out.flush();
}

我创建了一个Thread来接收来自服务器的命令,当两个客户端都连接到服务器时,它会向每个客户端发送一个字符串'ready'。我的想法是,主线程睡眠直到isOpponentConnected为真。

但是当我的游戏服务器失败并在第二个客户端连接到服务器时打印出一个nullpointer异常。我花了几天时间阅读并尝试修复此错误。当我在调试模式下运行代码时,两个客户端都收到就绪信号,并为两个客户端启动GUI。

Exception in thread "main" java.lang.NullPointerException
    at server.PlayerService.sendDataToClient(PlayerService.java:67)
    at server.GameServer.main(GameServer.java:23)

你们能看到任何我明显做错的事吗?

我认为这个问题非常有意义,因为它不仅仅是nullpointerexception,而是关于构建TCP服务器 - 客户端关系以及在初始化事物并准备线程和连接时准备好的链。

1 个答案:

答案 0 :(得分:0)

它应该可以从您发布的PlayerService.java类中修复 我建议搬家:

in = new Scanner(s.getInputStream());
out = new PrintWriter(s.getOutputStream());

public void run()到您的PlayerService构造函数:public PlayerService(Socket aSocket)
看起来函数sendDataToClient在初始化之前尝试使用out变量。