我正在用Java开发多线程非阻塞tcp服务器和客户端。我遇到服务器意识到客户端套接字已关闭的问题。对他而言,它始终是开放的。以下是我的代码的代码和输出:
服务器:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package androidnonblockingnewesttest;
import globalvariables.*;
import interface_package.*;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.InetSocketAddress;
import java.nio.channels.Channels;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
/**
*
* @author wsserver
*/
public class AndroidNonBlockingNewestTest {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
//Prevzemi staticen interface
GlobalVariables.sinterface = new ServerInterface();
GlobalVariables.sinterface.show();
//POSTAVI SERVER
//INFINITE LOOP
//NE MOZAM POSLE OVA DA POVIKUVAM NISTO BIDEJKI NEMA DA STIGNE DO NEGO PORADI while(true)
int port = GlobalVariables.portNo;
ServerSocketChannel serverSocket = null;
try {
serverSocket = ServerSocketChannel.open();
serverSocket.socket().bind(new InetSocketAddress(port));
serverSocket.configureBlocking(false);
System.out.println("Server has started listening on port " + port);
GlobalVariables.sinterface.setServerStatus("Server has started listening on port " + port);
GlobalVariables.sinterface.setReceivedText("Server has started listening on port " + port);
} catch (IOException e) {
System.out.println("Error: Cannot listen on port " + port + " : " + e);
GlobalVariables.sinterface.setServerStatus("Error: Cannot listen on port " + port + " : " + e);
GlobalVariables.sinterface.setReceivedText("Error: Cannot listen on port " + port + " : " + e);
System.exit(1);
}
while (true) // infinite loop - loops once for each client
{
SocketChannel clientSocket = null;
try {
clientSocket = serverSocket.accept(); //waits here (forever) until a client connects
if (clientSocket == null) {
// No connections came .
} else {
clientSocket.configureBlocking(false);
// You got a connection. Do something
System.out.println("Server has just accepted socket connection from a client");
GlobalVariables.sinterface.setServerStatus("Server has just accepted socket connection from a client");
GlobalVariables.sinterface.setReceivedText("Server has just accepted socket connection from a client");
// Create the Handle Connection object - our new thread object - only create it
ThreadedHandleConnection con = new ThreadedHandleConnection(clientSocket);
if (con == null) //If it failed send and error message
{
try {
ObjectOutputStream os = new ObjectOutputStream(Channels.newOutputStream(clientSocket));
os.writeObject("error: Cannot open socket thread");
GlobalVariables.sinterface.setReceivedText("error: Cannot open socket thread");
os.flush();
os.close();
} catch (Exception ex) //failed to even send an error message
{
System.out.println("Cannot send error back to client: " + ex);
GlobalVariables.sinterface.setServerStatus("Cannot send error back to client: " + ex);
GlobalVariables.sinterface.setReceivedText("Cannot send error back to client: " + ex);
}
} else {
con.start();
} // otherwise we have not failed to create the HandleConnection object
// start this thread now
}
} catch (IOException e) {
System.out.println("Accept failed: " + e);
GlobalVariables.sinterface.setServerStatus("Accept failed: " + e);
GlobalVariables.sinterface.setReceivedText("Accept failed: " + e);
break;
}
}
try // do not get here at the moment
{
System.out.println("Closing server socket.");
GlobalVariables.sinterface.setServerStatus("Closing server socket.");
GlobalVariables.sinterface.setReceivedText("Closing server socket.");
serverSocket.close();
} catch (IOException e) {
System.err.println("Could not close server socket. " + e.getMessage());
GlobalVariables.sinterface.setServerStatus("Could not close server socket. " + e.getMessage());
GlobalVariables.sinterface.setReceivedText("Could not close server socket. " + e.getMessage());
}
}
}
连接处理程序:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package androidnonblockingnewesttest;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
/**
*
* @author wsserver
*/
public class ThreadedHandleConnection extends Thread {
private SocketChannel clientSocket;
Charset charset = Charset.forName("ISO-8859-1");
CharsetEncoder encoder = charset.newEncoder();
CharsetDecoder decoder = charset.newDecoder();
ByteBuffer buffer = ByteBuffer.allocate(1024);
// The constructor for the connecton handler
public ThreadedHandleConnection(SocketChannel clientSocket) {
try {
this.clientSocket = clientSocket;
clientSocket.configureBlocking(false);
} catch (IOException ex) {
System.out.println("SocketChannel blocking exception: " + ex.getMessage());
}
}
// The main thread execution method
@Override
public void run() {
while (!clientSocket.socket().isClosed()) {
try {
System.out.println("Socket status:clientSocket.isConnected():" + clientSocket.isConnected());
System.out.println("Socket status:clientSocket.finishConnect():" + clientSocket.finishConnect());
System.out.println("Socket status:clientSocket.isOpen():" + clientSocket.isOpen());
System.out.println("Socket status:clientSocket.socket().isClosed():" + clientSocket.socket().isClosed());
System.out.println("Socket status:clientSocket.socket().isClosed():" + clientSocket.socket().isConnected());
int bytesread = clientSocket.read(buffer);
if (!(bytesread > 0)) {
System.out.println("Nothing to read");
} else {
buffer.flip();
String request = decoder.decode(buffer).toString();
System.out.println("Request:" + request);
buffer.clear();
}
Thread.sleep(3000);
} catch (IOException ex) {
System.out.println("Socket run exception " + ex.getMessage());
} catch (Exception ex) {
System.out.println("Exception " + ex.getMessage());
}
}
}
}
客户端:
package androidnonblockingnewesttest;
import globalvariables.GlobalVariables;
import java.io.*;
import java.net.*;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* @author wsserver
*/
public class ThreadedTCPClient {
private SocketChannel socket = null;
String serverIP = GlobalVariables.serverIP;
int port = GlobalVariables.portNo;
Charset charset = Charset.forName("ISO-8859-1");
CharsetEncoder encoder = charset.newEncoder();
CharsetDecoder decoder = charset.newDecoder();
ByteBuffer buffer = ByteBuffer.allocate(1024);
// the constructor expects the IP address of the server
public ThreadedTCPClient() {
if (!connectToServer()) {
System.out.println("Cannot open socket connection...");
}
}
private boolean connectToServer() {
try // open a new socket to port: and create streams
{
this.socket = SocketChannel.open();
this.socket.configureBlocking(false);
this.socket.connect(new InetSocketAddress("localhost", port));
while(!this.socket.finishConnect()){
}
System.out.print("Connected to Server\n");
} catch (Exception ex) {
System.out.print("Failed to Connect to Server\n" + ex.toString());
System.out.println(ex.toString());
return false;
}
return true;
}
public void sendTest() {
try {
buffer = encoder.encode(CharBuffer.wrap("Hellow from client"));
socket.write(buffer);
buffer.clear();
} catch (IOException ex) {
System.out.println("Write exception: "+ex.getMessage());
}
}
public void closeConnection(){
try{
this.socket.socket().close();
this.socket.close();
System.out.println("Close");
}catch(Exception ex){
System.out.print("Failed to close connection to Server\n" + ex.toString());
System.out.println(ex.toString());
}
}
public static void main(String args[]) {
ThreadedTCPClient theApp = new ThreadedTCPClient();
try {
Thread.sleep(10000);
theApp.sendTest();
theApp.closeConnection();
} catch (Exception ex) {
System.out.println(ex.toString());
}
}
}
这是我的骄傲。 来自客户的输出:
Connected to Server
Close
服务器输出:
Server has started listening on port 10001
Server has just accepted socket connection from a client
Socket status:clientSocket.isConnected():true
Socket status:clientSocket.finishConnect():true
Socket status:clientSocket.isOpen():true
Socket status:clientSocket.socket().isClosed():false
Socket status:clientSocket.socket().isClosed():true
Nothing to read
Socket status:clientSocket.isConnected():true
Socket status:clientSocket.finishConnect():true
Socket status:clientSocket.isOpen():true
Socket status:clientSocket.socket().isClosed():false
Socket status:clientSocket.socket().isClosed():true
Nothing to read
...
Socket status:clientSocket.isConnected():true
Socket status:clientSocket.finishConnect():true
Socket status:clientSocket.isOpen():true
Socket status:clientSocket.socket().isClosed():false
Socket status:clientSocket.socket().isClosed():true
Request:Hellow from client
Socket status:clientSocket.isConnected():true
Socket status:clientSocket.finishConnect():true
Socket status:clientSocket.isOpen():true
Socket status:clientSocket.socket().isClosed():false
Socket status:clientSocket.socket().isClosed():true
Nothing to read
...
从客户端关闭连接后,所有SocketChannel和SocketChannel.socket()状态都不会更改。请帮忙。
答案 0 :(得分:2)
您的代码在很多方面都是错误的。
如果你正在使用非阻塞I / O,你当然也应该使用Selector
,而不是在accept()
,finishConnect()
等中疯狂地旋转。
isClosed()
不会告诉您对等方是否已关闭。它会告诉您你是否已关闭。如果对等关闭,read()
将返回-1。同样,isConnected()
只会告诉您你是否连接了套接字。你做了,所以反复调用它是没有意义的。
在非阻止模式下进行连接的正确方法是(a)拨打connect(),
(b)在OP_CONNECT,
(c)拨打电话finishConnect()
时选择, (d)当且仅当该指示返回true时,取消OP_CONNECT.
如果您在非阻止模式下获得任何IOException
,则必须关闭该频道。
'多线程非阻塞服务器'在术语上是矛盾的。如果你有线程,阻止。如果您有非阻止模式,请选择。