简单服务器/客户端套接字:阻塞-java

iugsix8n  于 2021-06-30  发布在  Java
关注(0)|答案(2)|浏览(409)

我有一个客户机和一个服务器,这是一个典型的例子,试图用非常简单的方式模拟http协议。首先客户端发送数据,服务器端打印数据,然后相反。在下面的代码中,服务器或客户机阻塞,原因未知。客户机向服务器发送数据,服务器接收并打印数据。但它只是在打印完数据后阻塞。如果我关闭客户机的outputstream(out.close()),那么客户机应该获取服务器的数据,但会抛出ioexception,并显示消息:socket closed。
我的问题是为什么它会阻塞?我必须用eos触发输出吗?
客户

  1. import java.nio.*;
  2. import java.nio.channels.*;
  3. import java.net.*;
  4. import java.util.*;
  5. import java.io.IOException;
  6. import java.io.*;
  7. public class block_client_webclient
  8. {
  9. public static void main(String [] args)
  10. {
  11. try{
  12. Socket s = new Socket("localhost", 8080);
  13. OutputStreamWriter out = new OutputStreamWriter(s.getOutputStream());
  14. InputStreamReader in = new InputStreamReader(s.getInputStream());
  15. //WRITE
  16. out.write("GET / HTTP/1.1\r\nUser-agent: Agent 2.0 Browser\r\nAccept: */*\r\nAccept-Language: en-US,en;q=0.5\r\nConnection: keep-alive\r\n\r\n");
  17. out.flush();
  18. out.close();
  19. if (s.isConnected()==true && s.isClosed()==false) System.out.println("OPEN");
  20. else System.out.println("CLOSED");
  21. char[] bin = new char[400];
  22. int r=0;
  23. //READ
  24. while((r=in.read(bin))!=-1) { System.out.println("Input data: "+r+" bytes"); System.out.print(bin); bin= new char[400]; };
  25. System.out.println(r);
  26. s.close();
  27. }
  28. catch (IOException ex) {System.out.println(ex.getMessage());}
  29. }
  30. }

服务器

  1. import java.nio.*;
  2. import java.nio.channels.*;
  3. import java.net.*;
  4. import java.util.*;
  5. import java.io.IOException;
  6. import java.io.*;
  7. public class block_server_webserver
  8. {
  9. public static void main(String [] args)
  10. {
  11. while(true)
  12. {
  13. try{
  14. ServerSocket server = new ServerSocket(8080);
  15. Socket connection = server.accept();
  16. try{
  17. OutputStreamWriter out = new OutputStreamWriter( connection.getOutputStream());
  18. InputStreamReader in = new InputStreamReader( connection.getInputStream());
  19. char[] bin = new char[400];
  20. int r=0;
  21. int readsofar=0;
  22. //READ
  23. while((r=in.read(bin))!=-1) { System.out.print(bin); bin= new char[400]; };
  24. System.out.println("END");
  25. //WRITE
  26. out.write("Server: BlockServer 1.0\r\nHost: 192.168.1.1\r\n\r\n");
  27. out.flush();
  28. System.out.println("Just written data to "+connection.getRemoteSocketAddress());
  29. connection.close();
  30. } catch (IOException ex) { connection.close();}
  31. }catch (IOException ex) {}
  32. }
  33. }
  34. }
iyfamqjs

iyfamqjs1#

服务器不应该等待套接字关闭(因为一旦关闭,它将无法写回)。
它不应该一直读到返回-1(关闭),而应该读到请求的末尾(如果是http头,则是两行新行),并在这种情况下立即开始发送输出,然后,可能的话,关闭连接以通知客户端没有更多的数据(在http中,连接通常会保持打开状态一段时间,根据content length header,客户端知道在接收到足够的字节后停止读取。

e4yzc0pl

e4yzc0pl2#

执行out.close()会导致套接字关闭异常,因为当您关闭输入/输出流时,与之相关的套接字也会关闭。这意味着在客户端程序中,在关闭套接字后将无法读入。
首先,尝试创建一个“exit”字符串,而不是检查-1。如果服务器读取了退出字符串,那么识别出它需要停止在while循环中并中断(可以用一个简单的if语句完成)。另外,通常我会使用缓冲读取器stringx和readline(),而不是char array+read()。

  1. while (true) {
  2. in.read(bin);
  3. if (bin[0] == '^') { // or something like that
  4. break;
  5. }
  6. System.out.print(bin);
  7. bin = new char[400];
  8. }

只有在完全使用套接字后,才能使用close()流。

相关问题