Socket类的getInputStream方法与getOutputStream方法的使用

本文介绍了Socket类的getInputStream和getOutputStream方法在客户端与服务器端的使用,前者用于获取输入流接收数据,后者用于获取输出流发送数据。还阐述了read()和readLine()方法的阻塞特性,以及让程序从阻塞调用中返回的方法,如关闭输出流、约定数据长度、设置超时等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Socket类的getInputStream方法与getOutputStream方法的使用

客户端上的使用

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

服务器端上的使用

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

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


read()阻塞

从Socket上读取对端发过来的数据一般有两种方法:
1)按照字节流读取

BufferedInputStream in = new BufferedInputStream(socket.getInputStream());
int r = -1;
List<Byte> l = new LinkedList<Byte>();
        while ((r = in.read()) != -1) {
            l.add(Byte.valueOf((byte) r));
        }

2)按照字符流读取

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

这两个方法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);

代码实例:

public class TCPClient {
    public static void main(String[] args)throws IOException {
        Socket socket = new Socket("127.0.0.1",5000);
        OutputStream out = socket.getOutputStream();
   //创建文件对象     如果文件路径写错   Client报找不到文件异常,Server报Connection Reset异常
        File file = new File("E:\\Pictures\\010.jpg");  
           //字节输入流,读取本地文件到java程序中
        FileInputStream fis = new FileInputStream(file);
        byte[] data = new byte[1024];              //数组,增强传输效率
        int len = 0;
        while((len = fis.read(data)) != -1)   //read方法返回数组的有效字符个数
            out.write(data, 0, len);                              
        socket.shutdownOutput();  //数据传输完毕,关闭socket输出流,避免服务器端read方法阻塞

        InputStream in = socket.getInputStream();      //字节输入流,读取服务器返回的数据
        len = in.read(data);
        System.out.println(new String(data,0,len));

        socket.close();
        fis.close();
    }

   }

---------------------------------------------------------------------------------
public class TCPServer {
    public static void main(String[] args)throws IOException {
        ServerSocket server = new ServerSocket(5000);//打开服务器制定端口,等待客户端连接
        //获得与服务器相连的套接字对象     套接字:绑定ip地址和端口号的网络对象
        Socket socket = server.accept();
        //查看该地址文件夹是否存在,如果不存在,创建一个
        File file = new File("E:\\TestFolder\\upload"); 
        if(!file.exists()){
            boolean b = file.mkdirs();
            System.out.println(b);
        }   
        InputStream in = socket.getInputStream();  //套接字的字节输入流,读取客户端传过来的数据

        String name = System.currentTimeMillis()+""+new Random().nextInt(9999);        //随机文件名
        FileOutputStream fos = new FileOutputStream(file+File.separator+name+".jpg");  //File.separator表示分隔符,windows是\,linux是/             
        byte[] data = new byte[1024];
        int len = 0;
//如果客户端没有关闭socket输出流,这里的read方法会一直读取,对于socket流没有流末尾之说,不可能返回-1
        while((len = in.read(data)) != -1)  
            fos.write(data, 0, len);
        data = "上传成功!".getBytes();      //字符串转化为字节数组
        OutputStream out = socket.getOutputStream();     //创建字节输出流
        out.write(data);                //写入上传成功  ,反馈给客户端   
        server.close();
        fos.close();
    }

}

Socket是一种通信协议,可以在不同的计算机之间进行数据通信。而ServerSocket则是在服务器端监听客户端的连接请求,一旦有客户端连接,就可以创建一个新的Socket该客户端进行通信。 基本使用方法如下: 1. 创建ServerSocket对象,并指定端口号。 ```java ServerSocket serverSocket = new ServerSocket(8888); ``` 2. 循环监听客户端连接请求,接受客户端连接,并创建Socket对象。 ```java Socket socket = serverSocket.accept(); ``` 3. 使用输入输出流进行数据传输。 ```java InputStream inputStream = socket.getInputStream(); OutputStream outputStream = socket.getOutputStream(); ``` 4. 关闭Socket和ServerSocket对象。 ```java socket.close(); serverSocket.close(); ``` 完整的示例代码如下: ```java import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) { try { // 创建ServerSocket对象,并指定端口号 ServerSocket serverSocket = new ServerSocket(8888); System.out.println("服务器已启动,等待连接..."); while (true) { // 循环监听客户端连接请求,接受客户端连接,并创建Socket对象 Socket socket = serverSocket.accept(); System.out.println("客户端连接成功,IP地址为:" + socket.getInetAddress().getHostAddress()); // 使用输入输出流进行数据传输 InputStream inputStream = socket.getInputStream(); OutputStream outputStream = socket.getOutputStream(); byte[] buffer = new byte[1024]; int len = 0; while ((len = inputStream.read(buffer)) != -1) { String message = new String(buffer, 0, len); System.out.println("客户端发送的消息为:" + message); // 向客户端发送消息 String replyMessage = "已经收到您的消息:" + message; outputStream.write(replyMessage.getBytes()); outputStream.flush(); } // 关闭Socket对象 socket.close(); } } catch (IOException e) { e.printStackTrace(); } } } ``` 客户端的示例代码如下: ```java import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.util.Scanner; public class Client { public static void main(String[] args) { try { // 创建Socket对象,并指定服务器IP地址和端口号 Socket socket = new Socket("127.0.0.1", 8888); System.out.println("连接服务器成功!"); // 使用输入输出流进行数据传输 InputStream inputStream = socket.getInputStream(); OutputStream outputStream = socket.getOutputStream(); Scanner scanner = new Scanner(System.in); while (true) { System.out.print("请输入要发送的消息:"); String message = scanner.nextLine(); // 向服务器发送消息 outputStream.write(message.getBytes()); outputStream.flush(); byte[] buffer = new byte[1024]; int len = 0; if ((len = inputStream.read(buffer)) != -1) { String replyMessage = new String(buffer, 0, len); System.out.println("服务器返回的消息为:" + replyMessage); } } } catch (IOException e) { e.printStackTrace(); } } } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值