我已经编写了一个简单的客户端和服务器来教自己一些联网功能。它的设置方式是我有一个主服务器类,它将处理创建/销毁套接字,还有一个ConnectionThread类,它表示每个连接(每个连接都有自己的线程)。客户端超级简单。
问题在于在ConnectionThread类中创建输入/输出流。我不确定问题到底出在哪里,但是当简单的测试客户端尝试连接时,它崩溃了,这给了我:
~~MMO Server Alpha .1~~
Constructed Server
Server Initialized, preparing to start...
Server preparing to check if it should be listening...
Server should be listening, continuing as planned.
ServerSocket passed to ConnectionThread: ServerSocket[addr=0.0.0.0/0.0.0.0,localport=6969]
Constructing ConnectionThread.
Socket[addr=/10.0.1.10,port=55332,localport=6969]
ConnectionThread constructed.
Exception in thread "main" java.lang.NullPointerException
at ConnectionThread.init(ConnectionThread.java:65)
at Server.listen(Server.java:98)
at Server.start(Server.java:62)
at Server.main(Server.java:122)
ConnectionThread added to queue.
Establishing in and out streams:
null
以下是类(为简洁起见进行了修改):
public class Server {
int PORT;
boolean shouldListen;
ArrayList<ConnectionThread> connections = new ArrayList<ConnectionThread>();
ServerSocket serverSocket;
public Server() {
try {
PORT = 6969;
shouldListen = true;
serverSocket = new ServerSocket(PORT);
}
catch (IOException e) {
System.out.println("Error in server constructor.");
System.exit(1);
}
}
public void start() {
System.out.println("Server preparing to check if it should be listening...");
listen();
System.out.println("Server finished listening.");
}
public void listen() {
while (shouldListen) {
ConnectionThread conn = null;
System.out.println("Server should be listening, continuing as planned.");
try {
conn = new ConnectionThread(serverSocket);
}
catch (Exception e) {
System.out.println("____Error constructing ConnectionThread. Could there be another instance of the server running?");
System.exit(1);
}
System.out.println("ConnectionThread constructed.");
connections.add(conn);
System.out.println("ConnectionThread added to queue.");
conn.init();
System.out.println("Finished ConnectionThread initialization, verifying...");
if (conn.isInitialized) {
System.out.println("ConnectionThread Initialized, preparing to start new thread.");
(new Thread(conn)).start();
}
}
}
public static void main(String[] args) {
System.out.println("~~MMO Server Alpha .1~~");
Server server = new Server();
System.out.println("Constructed Server");
server.init();
System.out.println("Server Initialized, preparing to start...");
server.start();
}
}
这是ConnectionThread类:
public class ConnectionThread implements Runnable {
boolean shouldBeListening = true;
boolean isThereAnUnsentOutgoingMessage = false;
String outgoingMessage = "OUTGOING UNINITIALIZED";
boolean IsThereAnUnsentIncomingMessage = false;
String incomingMessage = "INCOMING UNITIALIZED";
boolean isInitialized = false;
PrintWriter out;
BufferedReader in;
String currentInputMessage = "Test Input Message from the Server ConnectionThread";
String previousInputMessage = null;
Socket socket;
public ConnectionThread(ServerSocket s) {
System.out.println("ServerSocket passed to ConnectionThread: " + s);
/*
* The purpose of the constructor is to establish a socket
* as soon as possible. All transmissions/logic/anything else
* should happen in init() and/or run().
*/
System.out.println("Constructing ConnectionThread.");
try {
Socket socket = s.accept();
System.out.println(socket);
}
catch (IOException e) {
System.out.println("Error in ConnectionThread constructor");
System.exit(1);
}
}
public void init() {
/*
* Everything should be set up here before run is called.
* Once init is finished, run() should be set to begin work.
* This is to ensure each packet is efficiently processed.
*/
try {
System.out.println("Establishing in and out streams:");
System.out.println(socket);
out = new PrintWriter(socket.getOutputStream(), true);
System.out.println("ConnectionThread: Output Stream (PrintWriter) Established");
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println("ConnectionThread: InputStream (BufferedReader) Established");
}
catch (IOException e) {
System.out.println("Error in ConnectionThread method Init.");
System.exit(1);
}
isInitialized = true;
}
可选地,这是测试客户端:
public class TestClient {
static PrintWriter out;
BufferedReader in;
public final int PORT = 6969;
Socket socket = null;
InetAddress host = null;
public TestClient() {
out = null;
in = null;
socket = null;
host = null;
}
public void connectToServer() {
System.out.println("Connecting to server...");
try {
host = InetAddress.getLocalHost();
socket = new Socket(host.getHostName(), PORT);
}
catch (Exception e) {
System.out.println("Error establishing host/socket");
System.exit(1);
}
try {
System.out.println("Establishing I/O Streams");
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
catch (Exception e) {
System.out.println("Error establishing in/out streams");
System.exit(1);
}
}
public static void main(String[] args) {
System.out.println("~~TestClient Alpha .1~~");
TestClient c = new TestClient();
c.connectToServer();
System.out.println("Should be connected to server. Sending test message...");
while (true) {
System.out.println("here");
out.println("Hello there");
}
}
}
最佳答案
ConnectionThread的构造函数中的“ socket”变量不应为本地变量。它遮盖了成员变量。
通常,在listen()循环中调用accept(),然后将接受的套接字传递给ConnectionThread。