我正在尝试构建一个简单的TCP多线程客户端/服务器应用程序。
每当客户端(Socket
)连接到ServerSocket
并发送与下面显示的简单可序列化类对应的Object
(Message
)时,服务器就会崩溃ObjectInputStream
1}}尝试从客户端Socket
读取SocketExpection
。
Message.java
package storageserver;
import java.io.Serializable;
public class Message implements Serializable {
private static final long serialVersionUID = 27015L;
public int ClientStatus; // 0 - NotLogged ::: 1 - Logged
public String Command;
public String[] Commands;
public Message()
{
this.ClientStatus = 0;
this.Command = null;
this.Commands = null;
}
public void createMessage(String msg)
{
this.Command = msg;
this.Commands = msg.split("\\s+");
}
}
StorageServer.java
package storageserver;
// imports..
public class StorageServer {
public static final int MAX_USERS = 250;
ServerSocket myServerSocket;
boolean serverOn = true;
File workingDir;
public StorageServer(int port, File dir) {
try {
InetAddress addr = InetAddress.getByName("192.168.1.73");
myServerSocket = new ServerSocket(port, MAX_USERS, addr);
workingDir = dir;
if(!workingDir.exists())
workingDir.mkdir();
System.out.println("StorageServer created successfully.");
} catch (IOException ex) {
Logger.getLogger(StorageServer.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("Could not create storage server on port 7000. Exiting.");
System.exit(-1);
}
}
public void listen()
{
System.out.println("Listening for connections...");
while(serverOn)
{
try {
//accepts incoming TCP connection
Socket clientSocket = myServerSocket.accept();
//starts new service thread to handle client requests in background
new ClientHandleThread(clientSocket).start();
}
catch (IOException e)
{
System.out.println("Exception encountered on accept. Ignoring. Stack Trace :");
e.printStackTrace();
}
}
try {
myServerSocket.close();
} catch (IOException ex) {
Logger.getLogger(StorageServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
class ClientHandleThread extends Thread {
private Socket myClientSocket;
private HashMap<String, Runnable> commandsMap;
private Message messageToSend, messageToReceive;
public ClientHandleThread() {
super();
}
public ClientHandleThread(Socket myClientSocket) {
this.myClientSocket = myClientSocket;
this.messageToSend = new Message();
this.messageToReceive = new Message();
}
private void help()
{
messageToSend.createMessage("Avaible commands:\n\n"
+ "exit -> Exits the App\n"
+ "stop -> Stops the server\n"
+ "dir -> Gets personal file's info in current server\n");
messageToSend.ClientStatus = 0;
}
@Override
public void run()
{
ObjectInputStream in = null;
ObjectOutputStream out = null;
System.out.println("Accepted connection from "
+ myClientSocket.getInetAddress().getHostAddress()+ ":" + myClientSocket.getPort());
try
{
System.out.println("IN..");
in = new ObjectInputStream(myClientSocket.getInputStream());
out = new ObjectOutputStream(myClientSocket.getOutputStream());
System.out.println("IN!");
messageToReceive = (Message) in.readObject(); //exception here - Software caused connection abort: recv failed
System.out.println("Client Says :" + messageToReceive.Command);
out.writeObject(messageToSend);
out.flush();
} catch (IOException | ClassNotFoundException ex) {
ex.printStackTrace();
Logger.getLogger(StorageServer.class.getName()).log(Level.SEVERE, null, ex);
}
finally
{
try
{
in.close();
out.close();
myClientSocket.close();
System.out.println("...Stopped");
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
}
}
调试输出
java.net.SocketException: Software caused connection abort: recv failed
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:170)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at java.net.SocketInputStream.read(SocketInputStream.java:223)
at java.io.ObjectInputStream$PeekInputStream.peek(ObjectInputStream.java:2303)
at java.io.ObjectInputStream$BlockDataInputStream.peek(ObjectInputStream.java:2596)
at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2606)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1319)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
at storageserver.StorageServer$ClientHandleThread.run(StorageServer.java:145)
nov 11, 2015 2:53:36 AM storageserver.StorageServer$ClientHandleThread run
可能导致此异常的原因是什么?我确定我不会在任何地方(客户端/服务器端)关闭或重置套接字连接。
在下面添加了客户端代码。
尝试receive()
来自服务器的响应时,客户端会收到异常。
TCPService.java(客户端)
package client;
//imports..
public class TCPService {
private Socket clientSocket;
public TCPService(String host, int port)
{
try {
clientSocket = new Socket(InetAddress.getByName(host), port);
clientSocket.setSoTimeout(5000);
} catch (IOException ex) {
System.err.println("Cant connect to Storage Server.\n" + ex);
System.exit(-1);
}
}
public Message receive()
{
try {
ObjectInputStream in = new ObjectInputStream(clientSocket.getInputStream());
try {
Message msg = (Message) in.readObject();
if(msg instanceof Message)
return msg;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} catch (IOException ex) {
Logger.getLogger(TCPService.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
public void send(Message msg)
{
try {
ObjectOutputStream oos = new ObjectOutputStream(clientSocket.getOutputStream());
oos.writeObject(msg);
oos.flush();
oos.close();
} catch (IOException ex) {
Logger.getLogger(TCPService.class.getName()).log(Level.SEVERE, null, ex);
}
}
//Main
public static void main(String[] args) throws IOException
{
/* Service Variable Declaration */
TCPService tcpService = new TCPService(args[0], args[1]);
/* Other Variables */
String buf = "";
Scanner scanIn = new Scanner(System.in);
Message msg = new Message();
isTCPRunning = true;
/* While-Loop for TCP Service */
while (isTCPRunning)
{
System.out.print("[User@StorageServer] Insert command: ");
buf = scanIn.nextLine();
msg.createMessage(buf);
scanIn.reset();
tcpService.send(msg);
msg = tcpService.receive(); //SocketException -> Socket Closed
System.out.println("[StorageServer] " + msg.Command);
tcpService.handleMessage(msg);
}
}
答案 0 :(得分:2)
发送消息后,客户端立即关闭ObjectOutputStream。这将关闭套接字的输出流,从而关闭套接字。当客户端尝试从输入流中读取时,套接字已经关闭,因此客户端上的异常。这也可能导致服务器端出现问题,因为在服务器读取数据时,TCP连接可能已经关闭。