我编写了一个小型的客户端/服务器程序,它已经工作过一次,但在添加了Threads和一些真正的输入数据之后,我总是得到一个封闭的Socket,然后才能读取Object(String)。程序始终打印“客户端已关闭连接!”来自ProcessDataThread中的函数handleConnection。
ClientCode:
synchronized private static void sendToServer(){
Socket clientSocket = null;
BufferedOutputStream socketOut = null;
ObjectOutputStream out = null;
try{
String xmlToSend = "<startTag>\n<someOtherTag id=\"5555\">\n12345\n</someOtherTag>\n</startTag>\n";
Log.d(TAG, "Trying to send the following to the Server:" + xmlToSend);
//TODO load these from file
clientSocket = new Socket( "10.0.2.2", 7777);
socketOut = new BufferedOutputStream(clientSocket.getOutputStream());
out = new ObjectOutputStream(socketOut);
out.writeObject(xmlToSend);
out.flush();
}catch(Exception ex){
Log.e(TAG, "Could not write File to Server.", ex);
}
finally{
try{
if(clientSocket != null){
clientSocket.close();
}
if(out != null){
out.close();
}
}catch(IOException ex){
Log.e(TAG, "Could not close Socket.");
}
}
}
ServerCode:
ReceiverThread:
public void run()
{
try {
ServerSocket server = new ServerSocket(port);
//Only block for 10 Seconds and try again
server.setSoTimeout(10000);
while(!server.isClosed() && !stopped){
//Run
Socket client = null;
try
{
client = server.accept();
System.out.println("Accepted ClientConnection from " + client.getRemoteSocketAddress());
new ProcessDataThread(client).start();
}
catch( SocketTimeoutException tx){
//nothing
}
catch ( IOException e ) {
e.printStackTrace();
}
finally {
if ( client != null )
try { client.close(); } catch ( IOException e ) { e.printStackTrace(); }
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
ProcessDataThread:
public class ProcessDataThread extends Thread {
Socket client;
public ProcessDataThread(Socket sock) {
// xmlToProcess = xmlString;
this.client = sock;
}
private String handleConnection() {
BufferedInputStream socketIn = null;
ObjectInputStream in = null;
String xmlToProcess = null;
try {
if(!client.isClosed()){
System.out.println("Trying to read from Stream;");
socketIn = new BufferedInputStream(client.getInputStream());
in = new ObjectInputStream(socketIn);
Object xmlString = in.readObject();
System.out.println("Read some Object from Stream:" + xmlString.toString());
if (xmlString instanceof String) {
xmlToProcess = (String) xmlString;
System.out.println("Received the following XML:\n" + xmlToProcess);
}
}else{
System.out.println("Client has already closed Connection!");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (EOFException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (socketIn != null) {
socketIn.close();
}
if(client != null){
client.close();
}
} catch (IOException ioex) {
ioex.printStackTrace();
}
}
return xmlToProcess;
}
@Override
public void run() {
String xmlToProcess = handleConnection();
if (xmlToProcess == null || xmlToProcess.isEmpty()) {
// Es konnte kein String vom Client gelesen werden.
return;
}
System.out.println(xmlToProcess);
}
}
我对jboi的建议做了一些改变。这就是我现在所拥有的。错误保持不变。我甚至没有阅读服务器中的Stream,因为client.getClosed()
总是如此!
在客户端代码中:
clientSocket = new Socket( "10.0.2.2", 7777);
clientSocket.setTcpNoDelay(true);
socketOut = new BufferedOutputStream(clientSocket.getOutputStream());
out = new ObjectOutputStream(socketOut);
out.writeObject(xmlToSend);
out.flush();
socketOut.flush();
//Close Output on Socket to signalize the Server that we finished writing!
clientSocket.shutdownOutput();
in = clientSocket.getInputStream();
byte[] receivedData = new byte[8192];
while(in.read(receivedData) != -1) {
//Wait for the Server to Close the Connection
}
在服务器代码中
socketIn = new BufferedInputStream(client.getInputStream());
in = new ObjectInputStream(socketIn);
Object xmlString = in.readObject();
System.out.println("Read some Object from Stream:" + xmlString.toString());
if (xmlString instanceof String) {
xmlToProcess = (String) xmlString;
System.out.println("Received the following XML:\n" + xmlToProcess);
}
out = client.getOutputStream();
out.write(1);
//Signalize the Client that we have read everything
client.shutdownOutput();
答案 0 :(得分:1)
问题似乎是客户端和服务器无法识别彼此的状态:
要么无法相互协调,要么解决方案是建立适当的状态机。 Google中的一些示例(如果您搜索(客户端和服务器状态机))会为您的应用程序提供数学上确定的状态机示例:希望此注释对您有所帮助。
因此,从解决方案的角度研究此问题并没有用处,并且可能开始使用诸如telnet等之类的协议。
答案 1 :(得分:0)
您不能在同一个套接字上使用缓冲输入流和另一种流。缓冲流将从另一个窃取数据。下定决心。 ObjectInputStream
将完成您需要的一切。只需使用它。
编辑重新编辑,&#39;套接字关闭&#39;表示你关闭你的套接字,然后继续使用它。
答案 2 :(得分:0)
在服务器能够读取数据之前,您的客户端很可能已关闭finally块中的套接字。
在你的客户端最终阻止你应该使用socket.shutdownOutput
,然后在客户端读取所有传入的数据,直到EOF,然后关闭套接字。
在你的服务器上,你读到EOF,然后发送一个对象作为一种确认,例如消息中的字节数。您也可以在客户端使用socket.shutdownOutput()
结束发送。这会在数据末尾再次显示EOF。客户端收到此EOF,它最终会关闭套接字。
答案 3 :(得分:0)
好吧,现在我感觉很蠢。 我自己关闭了服务器代码中的Socket。 接受连接后,在finally块中执行以下内容:
try {
client.close();
} catch (IOException e) {
e.printStackTrace();
}
最终阻塞的原因是因为我之前没有使用Threads,所以ReceiverThread也处理了Connection,因此在使用它之后关闭套接字。 然后我将代码移动到新的Thread并忘记删除最后一个块!