首页 > 其他 > 详细

socket通信模型、socket中accept阻塞的与read()阻塞

时间:2020-03-13 21:34:46      阅读:83      评论:0      收藏:0      [点我收藏+]

Socket整体流程

    Socket编程主要涉及到客户端和服务端两个方面,首先是在服务器端创建一个服务器套接字(ServerSocket),并把它附加到一个端口上,服务器从这个端口监听连接。端口号的范围是0到65536,但是0到1024是为特权服务保留的端口号,我们可以选择任意一个当前没有被其他进程使用的端口。

  客户端请求与服务器进行连接的时候,根据服务器的域名或者IP地址,加上端口号,打开一个套接字。当服务器接受连接后,服务器和客户端之间的通信就像输入输出流一样进行操作。

技术分享图片

 

客户端上的使用

  getInputStream()方法可以得到一个输入流,客户端的Socket对象上的getInputStream方法得到输入流其实就是从服务器端发回的数据。
  getOutputStream()方法得到的是一个输出流,客户端的Socket对象上的getOutputStream方法得到的输出流其实就是发送给服务器端的数据。

服务器端上的使用

  getInputStream()方法得到的是一个输入流,服务端的Socket对象上的getInputStream方法得到的输入流其实就是从客户端发送给服务器端的数据流。

  getOutputStream()方法得到的是一个输出流,服务端的Socket对象上的getOutputStream方法得到的输出流其实就是发送给客户端的数据。

 

ServerSocket类的accept()阻塞

ServerSocket的accept()方法是侦听并接受到此套接字的连接,就是一直等待连接,此方法在连接传入之前一直阻塞。直到接受到有socket的连接,然后创建并返回新的Socket对象。

 技术分享图片

read()阻塞

从Socket上读取对端发过来的数据一般有两种方法: 

1)按照字节流读取

1 BufferedInputStream in = new BufferedInputStream(socket.getInputStream());
2 int len = 0;
3 4         while ((len = in.read()) != -1) {
5             6         }

 

2)按照字符流读取

1 BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
2         String s;
3         while ((s = in.readLine()) != null) {
4             System.out.println("Reveived: " + s);
5         }

 

这两个方法read()和readLine()都会读取对端发送过来的数据,如果无数据可读,就会阻塞直到有数据可读。或者到达流的末尾,这个时候分别返回-1和null。 
这个特性使得编程非常方便也很高效。 
但是这样也有一个问题,就是如何让程序从这两个方法的阻塞调用中返回。

 总结一下,有这么几个方法:

 1、发送完后调用Socket的shutdownOutput()方法关闭输出流,这样对端的输入流上的read操作就会返回-1。  注意不能调用socket.getInputStream().close()。这样会导致socket被关闭。 

       当然如果不需要继续在socket上进行读操作,也可以直接关闭socket。  但是这个方法不能用于通信双方需要多次交互的情况。

 2、发送数据时,约定数据的首部固定字节数为数据长度。这样读取到这个长度的数据后,就不继续调用read方法。

 3、为了防止read操作造成程序永久挂起,还可以给socket设置超时。  如果read()方法在设置时间内没有读取到数据,就会抛出一个java.net.SocketTimeoutException异常。 

      例如下面的方法设定超时3秒。  socket.setSoTimeout(3000);

 

 代码示例:

 1 public class TCPClient {
 2     public static void main(String[] args)throws IOException {
 3         Socket socket = new Socket("127.0.0.1",5000);
 4         OutputStream out = socket.getOutputStream();
 5    //创建文件对象     如果文件路径写错   Client报找不到文件异常,Server报Connection Reset异常
 6         File file = new File("E:\\Pictures\\010.jpg");  
 7            //字节输入流,读取本地文件到java程序中
 8         FileInputStream fis = new FileInputStream(file);
 9         byte[] data = new byte[1024];              //数组,增强传输效率
10         int len = 0;
11         while((len = fis.read(data)) != -1)   //read方法返回数组的有效字符个数
12             out.write(data, 0, len);                              
13         socket.shutdownOutput();  //数据传输完毕,关闭socket输出流,避免服务器端read方法阻塞
14 
15         InputStream in = socket.getInputStream();      //字节输入流,读取服务器返回的数据
16         len = in.read(data);
17         System.out.println(new String(data,0,len));
18 
19         socket.close();
20         fis.close();
21     }
22 
23    }
24 
25 ---------------------------------------------------------------------------------
26 public class TCPServer {
27     public static void main(String[] args)throws IOException {
28         ServerSocket server = new ServerSocket(5000);//打开服务器制定端口,等待客户端连接
29         //获得与服务器相连的套接字对象     套接字:绑定ip地址和端口号的网络对象
30         Socket socket = server.accept();
31         //查看该地址文件夹是否存在,如果不存在,创建一个
32         File file = new File("E:\\TestFolder\\upload"); 
33         if(!file.exists()){
34             boolean b = file.mkdirs();
35             System.out.println(b);
36         }   
37         InputStream in = socket.getInputStream();  //套接字的字节输入流,读取客户端传过来的数据
38 
39         String name = System.currentTimeMillis()+""+new Random().nextInt(9999);        //随机文件名
40         FileOutputStream fos = new FileOutputStream(file+File.separator+name+".jpg");  //File.separator表示分隔符,windows是\,linux是/             
41         byte[] data = new byte[1024];
42         int len = 0;
43 //如果客户端没有关闭socket输出流,这里的read方法会一直读取,对于socket流没有流末尾之说,不可能返回-1
44         while((len = in.read(data)) != -1)  
45             fos.write(data, 0, len);
46         data = "上传成功!".getBytes();      //字符串转化为字节数组
47         OutputStream out = socket.getOutputStream();     //创建字节输出流
48         out.write(data);                //写入上传成功  ,反馈给客户端   
49         server.close();
50         fos.close();
51     }
52 
53 }

 

参考文章:

https://blog.csdn.net/anthony_ju/article/details/82192135

https://www.cnblogs.com/swordfall/p/10781281.html

socket通信模型、socket中accept阻塞的与read()阻塞

原文:https://www.cnblogs.com/FengZeng666/p/12488827.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!