java网络编程day02

双向传输数据

客户端代码

public class Clinet {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        InputStream is = socket.getInputStream();
        OutputStream os = socket.getOutputStream();
        os.write("你好,服务器端!".getBytes());
        //作为结束标志标志
        socket.shutdownOutput();
        byte[] read = new byte[1024];
        int readLine = 0;
        while ((readLine = is.read(read)) != -1) {
            System.out.println(new String(read, 0, readLine));
        }
        is.close();
        os.close();
        //socket.close();is和os关闭时就会关闭
    }
}

服务端代码

public class Server {
    public static void main(String[] args) throws IOException {
        //建立端口监听
        ServerSocket serverSocket = new ServerSocket(9999);
        //等待链接
        Socket socket = serverSocket.accept();
        //获取Socket输入输出流
        InputStream is = socket.getInputStream();
        OutputStream os = socket.getOutputStream();
        byte[] read = new byte[1024];
        int readLine = 0;
        //从网络管道中读取数据
        while ((readLine = is.read(read)) != -1) {
            System.out.println(new String(read, 0, readLine));
        }
        System.out.println("读入完毕");
        os.write("你好客户端!".getBytes());
        //socket.shutdoenOutput方法用来作为结束输出标志,如果不写会导致程序不知道什么时候读取完毕
        //socket.shutdownOutput();由于此程序后面没有内容,直接关流也能其同样的作用
        System.out.println("写入完毕");
        is.close();
        os.close();
        //socket.close();关闭socket返回的输入输出流时,socket也会被关掉,所以如果后面还要使用socket就不能用关流结束输出
        serverSocket.close();

    }
}

总结:

  1. 关闭socket对象返回的OutputStream/InputStream流时将同时关闭关联的套接字。
  2. 输出需要添加结束标志符,对字节输出流而言只能将流关闭,或者使用shutdownOutput方法暂时终止
  3. 一旦将流关闭,后面将没法使用socket对象,除非重新获取socket对象

使用字符流完成双向数据传输

客户端

public class Clinet {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        InputStreamReader isr = new InputStreamReader(socket.getInputStream());
        OutputStreamWriter osw = new OutputStreamWriter(socket.getOutputStream());
        BufferedReader bufferedReader = new BufferedReader(isr);
        BufferedWriter bufferedWriter = new BufferedWriter(osw);
        bufferedWriter.write("你好服务端");
        //必须刷新否则写入失败
        bufferedWriter.flush();
        //结束输出标记,可以用 osw.newLine() 替代,替代以后读取也必须用readLine读取
        socket.shutdownOutput();
        char[] read = new char[1024];
        int readLine = 0;
        while ((readLine = bufferedReader.read(read)) != -1) {
            System.out.println(new String(read, 0, readLine));
        }
        bufferedReader.close();
        bufferedWriter.close();
    }

服务器端

public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(9999);
        Socket socket = serverSocket.accept();
        OutputStreamWriter osw = new OutputStreamWriter(socket.getOutputStream());
        InputStreamReader isr = new InputStreamReader(socket.getInputStream());
        BufferedWriter bufferedWriter = new BufferedWriter(osw);
        BufferedReader bufferedReader = new BufferedReader(isr);
        char[] read = new char[1024];
        int readLine = 0;
        while ((readLine = bufferedReader.read(read)) != -1) {
            System.out.println(new String(read, 0, readLine));
        }

        bufferedWriter.write("你好客户端");
        bufferedWriter.flush();
        //socket.shutdownOutput();
        bufferedWriter.close();
        //socket.close();
        serverSocket.close();
    }

总结:

  1. 在字符流使用中可以使用newLine方法作为结束标识,但是想对应的读取的时候也必须用readLine方法读取
  2. 使用字符流写入时必须使用flush刷新流,否则写入失败抛出异常
  3. 关流迟出现的流后关准没错

shutdownOutput用处

禁用此套接字的输出流。对于 TCP 套接字,任何先前写入的数据都将按照 TCP 的正常连接终止顺序发送。如果在套接字上调用 shutdownOutput() 后写入套接字输出流,则该流将引发 IOException。

什么意思?

  1. 在客户端或者服务端通过socket.shutdownOutput()都是单向关闭的,即关闭客户端的输出流并不会关闭服务端的输出流,所以是一种单方向的关闭流;
  2. 通过socket.shutdownOutput()关闭输出流,但socket仍然是连接状态,连接并未关闭
  3. 如果直接关闭输入或者输出流,即:in.close()或者out.close(),会直接关闭socket

TCP网络通信编程不为人知的秘密

  1. 当客户端连接到服务器端后,实际上客户端也是通过一个端口和服务器进行通讯的,这个端口是TCP/IP来分配的,是不确定的,随机的
  2. windows下可以使用netstat命令验证端口号

UDP编程

  1. 没有明确的服务器端和客户端,眼变成数据的发送端和接受端
  2. 数据接受和发送是通过DatagramPacket对象(包含数据ip和端口)完成的
  3. 将数据封装成DaragramPacket对象传输(装包/拆包)
  4. 可以指定在哪个端口接受数据
posted @ 2022-03-22 00:38  ふじさんのゆき  阅读(24)  评论(0编辑  收藏  举报