java网络编程

网络编程

网络基础知识:

IP地址:

  1. 唯一标识主机
  2. 对于IPV4来说有4个字节,一个字节范围为0~255
  3. ip地址的组成192.168.1.110 网络地址+主机地址
  4. IPV6是由于IPV4地址不够用,用于替代IPV4的下一代IP协议

1641711962551

域名和端口号:

  1. 域名方便记忆(IP地址)
  2. IP地址找到主机,端口号找到主机里的不同服务
  3. 在开发中,不要使用0-1024的端口,这些端口一般名花有主了

网络协议(为了让两台主机能够数据传输):

中国人跟中国人说话,听得懂,

你用中国话跟外国人说话,外国人听不懂,语言就是一个协议

而计算机和计算机之间,数据的组织形式,也就是一种协议

1641714296879

TCP和UDP:

TCP:传输控制协议

双向奔赴的爱情,找一个值得的人慢,但是可靠,可以付出很多感情(大量数据)

  1. 传输前必须三次握手,确认可以进行大量数据传输,可靠

  2. 通信的两个应用进程:客户端,服务端

  3. 传输完毕后,需要释放已建立的连接,效率低

    三次握手:

客户端 发送消息x给服务器,服务器回应消息x+1和y给客户端,客户到收到x+1确定服务器可以连接到,再发送y+1给服务器,服务器收到,确定客户端收到了自己的消息,正常开始传输

UDP:用户数据协议

不认真对待的爱情很容易找到,快,但是不可靠,不能付出太多感情(不适合传输大量数据)

  1. 不需要建立连接,不可靠
  2. 不适合传输大量数据
  3. 发送接受不需要关闭连接,速度快

InetAddress:

用处:获取本地的ip地址和主机名,通过域名获取其他主机的ip地址和主机名

    public static void main(String[] args) throws UnknownHostException {
//        1.获取本机的InetAdddress对象
        InetAddress localHost =InetAddress.getLocalHost();
        System.out.println(localHost);
//        2.根据主机名获取InetAdddre对象
        InetAddress byName = InetAddress.getByName("Producer-2021XC");
        System.out.println(byName);
//        3.根据域名返回InetAdddre对象
        InetAddress byName1 = InetAddress.getByName("www.baidu.com");
        System.out.println(byName1);
//        4.通过对象获取地址
        String hostAddress = byName1.getHostAddress();
        System.out.println(hostAddress);
//        5.通过对象获取主机名/或者域名
        String hostName = byName.getHostName();
        System.out.println(hostName);
    }

Socket:

1641716725465

  1. 套接字
  2. 通信两端都有Socket,是通信的端点
  3. 网络通信其实就是Socket的通信
  4. Socket使网络连接成一个流,数据在两个Socket间通过Io传输
  5. 底层使用的是TCP/IP协议

TCP字节流编程:

基础流程:

  1. 客户端和服务端是靠socket的数据通道进行传输的
  2. 启动顺序:必须先启动服务端,再开启客户端,服务端要先监听,而且客户端要是开启,去获取连接也获取不到
  3. 服务端:获取监听 》获取socket 》获取输入流
  4. 客户端:获取连接(ip地址,端口号)》 获取输入流
  5. 每发送完一次信息要记得,设置结束标志

字节流的传输:

服务端:
    public static void main(String[] args) throws IOException {
//        思路:
//        1.首先拿到端口号为9999的监听
//        要求没用其他服务监听9999
//        这个serverSocket可以返回多个accept,多个客户端来连接服务器并发
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("===开始监听===");
//        2.接收连接,如果没用客户端连接上这个端口就会阻塞
        Socket accept = serverSocket.accept();
        System.out.println("成功获取客户端连接");
//        3.通过输入流接收客户端消息
        InputStream IS = accept.getInputStream();
        System.out.println(IS.getClass());
        byte[]buf=new byte[1024];
        int readlend=0;
        while ((readlend=IS.read(buf))!=-1){
            System.out.println(new String(buf,0,readlend));
        }
        System.out.println("服务端关闭");
        IS.close();
        accept.close();
        serverSocket.close();
    }
客户端 
public static void main(String[] args) throws IOException {
//        思路:
//        1.连接服务器(ip,端口)
        Socket socket = new Socket(InetAddress.getLocalHost(),9999);
//        2.连接后,生成Socket
        OutputStream OS = socket.getOutputStream();
//        3.通过输出流,写入数据到数据管道
        OS.write("hello,server".getBytes());
        System.out.println("客户端关闭");
        OS.close();
        socket.close();
    }

回传:

当客户端发送后,要接收服务端的回传信息,服务端收到后,要向客户端发送消息

注意点:传完(接收)后要设置接收接收标记,不然socket会不知道你是否完成,造成堵塞

accept.shutdownInput();

accept.shutdownOutput();

服务端
public static void main(String[] args) throws IOException {
//        服务端只需要写当前服务的端口号就行了
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("服务端打开");
        Socket accept = serverSocket.accept();
        System.out.println("获取接收信息:");
        InputStream IS = accept.getInputStream();
        OutputStream OS = accept.getOutputStream();
        byte buf[]=new byte[1024];
        int readline=0;
        System.out.println("接收到客户端信息");
        while ((readline=IS.read(buf))!=-1){
            System.out.println(new String(buf,0,readline));
        }
        //        设置结束标记
        accept.shutdownInput();
        System.out.println("向客户端回传信息");
        OS.write("hello,client".getBytes());
        IS.close();
        OS.close();
        accept.close();
        serverSocket.close();
    }
}
客户端 
public static void main(String[] args) throws IOException {
        Socket socket = new Socket(InetAddress.getLocalHost(),9999);
        OutputStream OS = socket.getOutputStream();
        InputStream IS = socket.getInputStream();
        System.out.println("向服务端发送信息:");
        OS.write("hello,server".getBytes());
//        设置结束标记
        socket.shutdownOutput();
        byte buf[]=new byte[1024];
        int readline=0;
        System.out.println("接收服务端信息");
        while ((readline=IS.read(buf))!=-1){
            System.out.println(new String(buf,0,readline));
        }
        IS.close();
        OS.close();
        socket.close();
    }

用字符流传递字符串

转换流转成字符流(字符流写入后要flush,不然数据进不到管道)其他一样

涉及缓存必须flush

下载文件/上传文件:

思路:

客户端:先读取本地资源,再用socket的输出流,输出到服务端

服务端:先读取socket输入流,再输出到本地磁盘

1641796937924

注意点:

当客户端连接到服务端后,实际上客户端也是通过一个端口来跟服务器连接的,并且不是跟服务端相同的端口,这个端口是由TCP/IP随机分配,不确定

输入流或者输出流不能在shutdownOutput或者另外一个前先退出,不然会造成socket close异常,也就是你的流不能在标记前退出,可能消息没完

netstat:

  1. netstat - an查看主机网络情况

  2. netstat - an | more分页查看

  3. Listening表示那个端口在监听

  4. 1641782586301

UDP网络编程:

基础流程:

  1. 特点就是UDP不在乎对方是否收到
  2. 通过DategramSocket和DategramPacket(数据包)实现了UDP协议网络程序
  3. 没有明确的服务端和客户端,只有发送端和接收端,所以是通过DategramSocket接收和发送
  4. 通过DategramPacket封装数据,既然封装了数据,就肯定有拆包的过程
A端  
public static void main(String[] args) throws IOException {
        DatagramSocket datagramSocket = new DatagramSocket(8888);
        while (true){
            Scanner scanner = new Scanner(System.in);
//        发送包并发送数据
            System.out.println("发送消息:");
            String content = scanner.next();
            if (content.equals("退出")){
                break;
            }
            DatagramPacket packetSE = new DatagramPacket(content.getBytes(StandardCharsets.UTF_8), content.length(), InetAddress.getLocalHost(), 9999);
            datagramSocket.send(packetSE);

            //接收包并输出消息
            byte []byteRE=new byte[1024];
            DatagramPacket packetRE = new DatagramPacket(byteRE,byteRE.length);
            datagramSocket.receive(packetRE);
            int length = packetRE.getLength();
            byte[] data = packetRE.getData();
            System.out.println("收到B端的消息:"+new String(data,0,length));

        }
        System.out.println("A端退出");
    }
B端   
public static void main(String[] args) throws IOException {
        DatagramSocket datagramSocket = new DatagramSocket(9999);
        while (true){
            //        接收包并输出消息
            byte []byteRE=new byte[1024];
            DatagramPacket packetRE = new DatagramPacket(byteRE,byteRE.length);
            datagramSocket.receive(packetRE);
            System.out.println("收到A端");

            int length = packetRE.getLength();
            byte[] data = packetRE.getData();
            String s = new String(data, 0, length);
            System.out.println("收到A端的消息:"+s);
            if ("退出".equals(s)){
                break;
            }
//        发送包并发送数据
            System.out.println("发送消息");
            Scanner scanner = new Scanner(System.in);
            String content = scanner.next();
            DatagramPacket packetSE = new DatagramPacket(content.getBytes(StandardCharsets.UTF_8), content.length(), InetAddress.getLocalHost(), 8888);
            datagramSocket.send(packetSE);

        }
        System.out.println("B端退出");
    }

注意点:

UDP网络编程没有客户端和服务端,都是用DatagramSocket接收和发送,DatagramSocket可以设置不同端路自己的端口号

总结:

  1. 网络基础知识方面要知道网络中,不同设备的传输,需要IP地址,不同服务的传输需要端口号
  2. 可以通过InetAddress获取本地的IP地址和端口号等信息
  3. Socket套接字,底层是TCP/IP在服务端和客户端都有一个套接字,两个端通过Socket的数据通道传输数据,记住客户端也有端口号,并且是TCP/IP随机分配的,我们可以通过套接字获取到输出和输入的流,套接字会把流放进数据通道进行传输
  4. TCP网络编程,服务端需要获取监听,没有收到客户端的连接就会阻塞,然后通过套接字输入流获取客户端传来的信息客户端需要获取套接字并通过IP地址和端口号绑定到服务端,通过输出流将数据输出给服务端
  5. UDP网络编程,UDP没有服务端和客户端,只有接收端和发送端,并且每一个端都可以是,通过对象DatagramSocket进行接收和发送,通过Datagramapack进行封装数据,接收端要拆包,设置接收的字节数组和长度,客户端设置传入的字节数组和IP地址,端口号
posted @ 2022-03-14 18:07  又菜又ai  阅读(56)  评论(0)    收藏  举报