因此,我对套接字和数据流还很陌生...我绝对对这个问题感到困惑。假设其他人可能遇到我遇到的相同问题,我已经花了数小时试图找到解决方案,但是到目前为止,我发现绝对没有任何帮助。
我正在编写一个非常简单的多线程服务器/客户端程序,该程序应该打开serverSocket,并接受来自客户端的连接,并将它们存储在一个简单的arraylist中(一旦我实际收到要发送的消息,我将更改存储过程。 ),然后消息处理程序线程解析该列表,并检查用户是否已写入服务器。如果用户已经写了一些东西,则程序将结果消息显示到控制台。我的程序通过DataOutputStream成功写入服务器套接字,但是当我尝试从服务器端的相应DataInputStream读取时,它说该流为空,并且我的程序将继续循环。我已经检查过DataOutputStream是否通过DataOutputStream.size()接收到数据,并且我尝试从中读取数据的DataInputStream对应于我之前提到的正确的DataOutputStream。
用户代码:
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;
public class User {
private String hashID;
private Socket connection;
private static int hashVal = 0;
DataInputStream consoleInputStream;
String consoleInput = "";
public User(Socket conn) throws SocketException {
hashID = hashUserKey();
connection = conn;
connection.setSoTimeout(1500);
consoleInputStream = new DataInputStream(System.in);
}
private static String hashUserKey() { //placeholder for now
hashVal++;
return("Guest" + hashVal);
}
public Socket getSocket() {
return this.connection;
}
public String getID() {
return this.hashID;
}
public boolean disconnect() {
try {
consoleInputStream.close();
connection.close();
return true;
} catch (IOException e) {
System.err.println(hashID + " was unable to successfully disconnect");
return false;
}
}
public void startConnection() {
new Thread() {
@Override
public void run() {
while(!connection.isClosed()) {
try {
consoleInput = consoleInputStream.readLine();
if(consoleInput != null || consoleInput != "") {
writeToServer(consoleInput);
}
} catch (IOException e) {
System.err.println("Was not able to read console input");
}
}
System.out.println("You were disconnected, have a nice day!");
return;
}
}.start();
}
private boolean writeToServer(String toWrite) {
try {
String msg = hashID + ">>>: " + toWrite;
DataOutputStream outStream = new DataOutputStream(connection.getOutputStream());
outStream.writeUTF(toWrite + "\r\n");
outStream.flush();
consoleInput = "";
System.out.println(msg + "\t was written to " + connection.getInetAddress() + ":" + connection.getPort());
return true;
} catch (IOException e) {
System.err.println(hashID + " was unable to write to server");
return false;
}
}
@Override
public boolean equals(Object o) {
User t = (User) o;
if(t.hashID == this.hashID) {
return true;
}
return false;
}
}
服务器代码:
import java.net.*;
import java.io.*;
import java.util.*;
public class TestServer {
private static ServerSocket server;
private static TestLogger logger;
private static Thread serverHandlerThread;
private static Thread messageHandlerThread;
private static ArrayList<User> users;
private static volatile boolean hasBeenStopped = false;
public static boolean startServer(int port) {
logger = new TestLogger();
logger.log("Attempting to create default shutdown behavior for server");
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
if(!hasBeenStopped) {
logger.warn("Server was shut down without running stopServer(), running by default");
stopServer();
}
}
}
);
logger.log("Shutdown behaivor created. Now attempting to set up user database"/*TODO create a real database*/);
users = new ArrayList<User>();
logger.log("Attempting to start server");
try {
server = new ServerSocket(port);
logger.log("Server successfully started at " + server.getInetAddress() + ":" + server.getLocalPort() +", now attempting to start user connection handler");
serverHandlerThread = new Thread() {
@Override
public void run() {
this.setName("serverHandlerThread");
while(!server.isClosed()) {
try {
Socket temp = server.accept();
logger.log("Connection accepted from " + temp.getInetAddress());
System.out.println("Connection accepted from " + temp.getInetAddress());
startUserConnection(new User(temp));
} catch (SocketException e) {
logger.warn("Server was closed while in accept phase");
} catch (IOException e) {
e.printStackTrace();
}
}
logger.log(this.getName() + " was stopped, server socket was closed successfully");
return;
}
};
serverHandlerThread.start();
logger.log("Server thread successfully started, listening for connections on: " + server.getInetAddress().toString() + ":" + port);
logger.log("Attempting to start message handler thread to read user inputs");
messageHandlerThread = new Thread() {
@Override
public void run() {
this.setName("messageHandlerThread");
while(!server.isClosed()) {
if(users.isEmpty()) {
continue;
}
for(int i = 0; i < users.size(); i++) {
User temp = users.get(i);
try {
System.out.println(new DataInputStream(temp.getSocket().getInputStream()).readUTF());
} catch (IOException e) {
System.err.println("Nothing to read from client: " + temp.getID());
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
};
messageHandlerThread.start();
return true;
} catch (IOException e) {
logger.error("Could not bind server socket to port.");
return false;
}
}
public static boolean stopServer() {
logger.log("Started shut down process");
if(serverHandlerThread == null || !serverHandlerThread.isAlive()) {
logger.warn("Thread has not been started yet or has already been killed");
return false;
}
else {
stopAllUserConnections();
try {
server.close();
hasBeenStopped = true;
while(serverHandlerThread.isAlive()) {
}
logger.log("Server was successfully shut down");
return true;
} catch (IOException e) {
logger.error("Could not close server socket");
return false;
}
}
}
private static void startUserConnection(User user) {
logger.log("Connected new user from " + user.getSocket().getInetAddress());
users.add(user);
System.out.println(user.getID() + " was added to list");
user.startConnection();
}
private static boolean stopUserConnection(User user) {
logger.log("Attempting to disconnect user, address: " + user.getSocket().getInetAddress());
for(User u : users) {
if(u.equals(user)) {
u.disconnect();
return true;
}
}
logger.warn("Could not find user with address: " + user.getSocket().getInetAddress());
return false;
}
private static boolean stopAllUserConnections() {
logger.log("Attempting to disconnect all users from the server");
if(users.isEmpty()) {
logger.warn("No users available to disconnect");
return false;
}
for(User u : users) {
u.disconnect();
}
users.clear();
return true;
}
public static void main(String args[]) {
startServer(*the_port*);
Client c = new Client();
c.connect("0.0.0.0", *the_port*);
}
}
客户代码:
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client {
public boolean connect(String serverName, int port) {
try {
System.out.println("Attempting to connect");
Socket sock = new Socket(serverName, port);
System.out.println("Connected");
return true;
} catch (UnknownHostException e) {
System.err.println("Could not resolve " + serverName + ":" + port);
}
catch (IOException e) {
e.printStackTrace();
}
return false;
}
}
因此,正如我在上文中所述,在我尝试读取写入服务器的数据之前,此方法都可以正常工作。不管我做什么,服务器对套接字上的readUTF()的调用始终会抛出IOException,并且使用DataInputStream.available()检查准备读取的字节也将返回0。我最近一次运行的示例输出如下:
Attempting to connect
Connected
Connection accepted from *the_address*
Guest1 was added to list
Nothing to read from client: Guest1
Nothing to read from client: Guest1
Nothing to read from client: Guest1
test
Guest1>>>: test was written to *the_address:another_port*
Nothing to read from client: Guest1
Nothing to read from client: Guest1
Nothing to read from client: Guest1
我知道我的代码可能已经过优化,我将在稍后进行修复,但是现在,我想知道的是为什么刷新对应的DataOutputStream后DataInputStream为空,以及如何成功发送UTF他们之间的数据。