【Java笔记】(六):网络编程

什么是网络编程

在网络通信协议下,实现网络互联的不同计算机上运行的程序可以进行资源交换,简而言之,用户之间可以发送消息或文件

在这里插入图片描述

网络编程三要素

IP地址

IP地址是网络中设备的唯一标识,分为IPv4和IPv6两大类,我们使用IPv4进行网络通信,它采用点分十进制表示法,一般长这样192.168.99.1127.0.0.1可以代表本机地址,一般用于测试

命令 说明
ipconfig 查看本机IP
ping IP 检查网络是否连通

端口

网络的通信本质上是两个应用程序的通信,每台计算机上有许多程序,每个程序都运行在某一个端口上,端口号可以作为应用程序的唯一标识,普通应用程序要使用1024之后的端口号

协议

在计算机网络中,连接和通信的规则称为网络通信协议,它对数据的传输格式、传输速率、传输步骤等做了统一规定,通信双方必须同时遵守才能完成数据交换,常见的协议有TCP协议和UDP协议

TCP协议是面向连接的通信协议,可以为两台计算机提供可靠无差别的数据传输,在TCP协议中必须明确客户端与服务器,由客户端向服务器发起连接请求,每次连接要经过三次挥手

UDP协议是面向无连接的通信协议,,不管对方有没有收到,反正只负责发出去,由于UDP耗费资源小,通信效率高,通常会用于传输音频、视频、和普通数据以及直播

关于三次握手,四次挥手的理解

三次握手以及四次挥手其实就是确保客户端和服务器知道彼此都具备接收和发送数据的能力,以及做好了分开的准备,其中,以三次挥手为例。

  • 客户端发起连接请求,服务器知道客户端有发送数据的能力,但是不知道客户端有没有接收的能力,与此同时,客户端不知道服务器是否具备接收和发送数据的能力
  • 服务器回送响应,客户端知道服务器有了接受和发送数据的能力
  • 客户端发送确认信息,服务器知道客户端接收到了上次的响应,服务器知道客户端有了接收数据的能力

在这里插入图片描述

InetAddress的使用

InetAddress是Java提供的一个类,方便我们对IP地址进行获取和操作

public class MyInetAddress {
    
    
    public static void main(String[] args) throws UnknownHostException {
    
    
        //通过主机名或ip地址获取对象
        InetAddress address = InetAddress.getByName("192.168.99.1");
        //获取主机名
        String hostName = address.getHostName();
        System.out.println("主机名:"+hostName);
        //获取IP地址字符串
        String hostAddress = address.getHostAddress();
        System.out.println("IP地址:"+hostAddress);
    }
}

UDP发送数据

Java提供了DatagramSocket类基于UDPP协议的Socket

扫描二维码关注公众号,回复: 12886891 查看本文章

发送数据的步骤:

  • 创建Socket对象
  • 创建数据并将数据打包
  • 调用DatagramSocket对象的方法发送数据
  • 关闭发送端
public class TcpSendDemo {
    
    
    public static void main(String[] args) throws Exception {
    
    
        String hostName = "192.168.99.1";
        int port = 6666;
        //创建socket对象
        DatagramSocket socket = new DatagramSocket();
        //准备数据,控制台读取
        System.out.print("请输入你要发送的内容:");
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        String text = reader.readLine();
        byte[] data = text.getBytes();
        //将数据打包
        DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getByName(hostName),port);
        //发送数据
        socket.send(packet);
        socket.close();
    }
}

UDP接收数据

接收数据的步骤:

  • 创建接收端的Socket对象
  • 创建一个数据包,用于接收数据
  • 调用DatagramSocket对象的方法接收数据
  • 解析数据包,并把数据在控制台显示
  • 关闭接收端
public class UdpReceiveDemo {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //UDP接收只需要知道端口号就可以了
        int port = 6666;
        //创建socket对象
        DatagramSocket socket = new DatagramSocket(port);
        //创建一个数据包接收数据
        byte[] bytes = new byte[1024];
        DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
        //调用方法接收数据,阻塞等待
        socket.receive(packet);
        //解析数据包
        byte[] data = packet.getData();
        int length = packet.getLength();
        //这里指定长度是消除后面的空字符,因为有时候不够1024
        String dataString = new String(data, 0, length);
        System.out.println("收到:"+dataString);
        //关闭
        socket.close();
    }
}

TCP客户端发送数据

客户端和服务端会建立虚拟链路,是通过这个虚拟链路进行通信的。Java对基于TCP协议的网络提供了良好的封装,使用Socket对象来代表两端的通信端口,并通过Socket产生IO流来进行网络通信

在这里插入图片描述

发送数据的步骤:

  • 创建客户端的Socket对象
  • 获取输出流,写数据
  • 释放资源
public class TcpClientDemo {
    
    
    public static void main(String[] args) throws IOException {
    
    
        String hostName = "192.168.99.1";
        int port = 7777;

        //创建客户端对象
        Socket socket = new Socket(hostName, port);
        //获取输出流,写数据
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("你好啊,tcp".getBytes());
        //通知服务端,我传输完了
        socket.shutdownOutput();
        //得到服务器反馈
        InputStream inputStream = socket.getInputStream();
        byte[] bytes = new byte[1024];
        int len = inputStream.read(bytes);
        String dataString = new String(bytes, 0, len);
        System.out.println("接收到服务器:"+dataString);
        //释放资源
        socket.close();
    }
}

TCP服务器接收发送数据

接收数据的步骤:

  • 创建服务器的Socket对象ServerSocket
  • 获取输入流,读数据,把数据显示
  • 释放资源
public class TcpServerDemo {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //创建ServerSocket对象
        ServerSocket serverSocket = new ServerSocket(7777);
        //监听socket的连接
        Socket accept = serverSocket.accept();
        //获取输入流,读数据
        InputStream inputStream = accept.getInputStream();
        byte[] bytes = new byte[1024];
        //一种是读字节,另一种是读字节数组,文本东西少,读一遍就好了
        int len = inputStream.read(bytes);
        String dataString = new String(bytes, 0, len);
        System.out.println("接收客户端到:"+dataString);
        //返回信息
        OutputStream outputStream = accept.getOutputStream();
        outputStream.write("已成功接收!".getBytes());
        //关闭资源
        serverSocket.close();
        accept.close();
    }
}

TCP中socket的补充

服务器可以通过accept方法获取道连接的socket,这个socket可以获取输入流(客户端传到服务器的信息),然后将输入流写入字符数组。同时这个accept得到的socket对象也可以获取输出流,用同样的套路去给客户端写东西,客户端的socket使用socket.getInputStream()方法,使用同样的套路去获取服务器的信息

BufferedWriter的应用

在写的时候可以使用封装了OutputStream的BufferBuilder,直接调用write方法,将字符流转为字节流,功能等同于输出流的write。将getOutputStream字节输出流转化为了OutputStreamWriter字符输出流,再采用BufferedWriter写数据

public class TcpClientDemo {
    
    
    public static void main(String[] args) throws IOException {
    
    
        String hostName = "192.168.99.1";
        int port = 7777;

        //创建客户端对象
        Socket socket = new Socket(hostName, port);
        //字符输入流
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        String text = reader.readLine();
        //获取输出流,写数据
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        String line;
        while ((line=reader.readLine())!=null) {
    
    
            bufferedWriter.write(line);
            bufferedWriter.newLine();
            bufferedWriter.flush();
        }
        //释放资源
        socket.close();
    }
}

BufferedReader的应用

将字节流直接转为字符流

public class TcpServerDemo {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //创建ServerSocket对象
        ServerSocket serverSocket = new ServerSocket(7777);
        //监听socket的连接
        Socket accept = serverSocket.accept();
        //获取输入流,读数据
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(accept.getInputStream()));
        String line;
        while ((line=bufferedReader.readLine())!=null) {
    
    
            System.out.println("接收客户端到:"+line);
        }

        serverSocket.close();
        accept.close();
    }
}

TCP服务器内容写入文本文件

FileWriter封装为bufferedWriter,客户端代码可以用上面的BufferedWriter的应用的代码

public class TcpServerDemo {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //创建ServerSocket对象
        ServerSocket serverSocket = new ServerSocket(7777);
        //监听socket的连接
        Socket accept = serverSocket.accept();
        //获取输入流,读数据
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(accept.getInputStream()));
        //把数据写入文本文件
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("a.txt"));
        String line;
        while ((line=bufferedReader.readLine())!=null) {
    
    
            bufferedWriter.write(line);
            bufferedWriter.newLine();
            bufferedWriter.flush();
        }
        bufferedReader.close();
        bufferedWriter.close();
        serverSocket.close();
        accept.close();
    }
}

TCP客户端内容来自文本文件

服务器的程序和上面TCP服务器内容写入文本文件是一样的

public class TcpClientDemo {
    
    
    public static void main(String[] args) throws IOException {
    
    
        String hostName = "192.168.99.1";
        int port = 7777;

        //创建客户端对象
        Socket socket = new Socket(hostName, port);
        //字符输入流,读数据
        BufferedReader bufferedReader = new BufferedReader(new FileReader("b.txt"));
        //获取输出流,写数据
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        String line;
        while ((line=bufferedReader.readLine())!=null) {
    
    
            bufferedWriter.write(line);
            bufferedWriter.newLine();
            bufferedWriter.flush();
        }
        //释放资源
        bufferedReader.close();
        bufferedWriter.close();
        socket.close();
    }
}

多线程实现文件上传

服务器一直开着,每来一个客户端就开一个线程,实现思路如下:

创建一个实现了Runnable接口的类,构造方法中的参数是Socket类型,文件上传操作放在run方法中,服务器使用while死循环,accept得到的对象传入线程,然后调用start方法

猜你喜欢

转载自blog.csdn.net/m0_46521785/article/details/114705020