Skip to content

二十、网络编程

一、什么是网络编程

在网络通信协议下,不同计算机上运行的程序,进行的数据传输

二、软件架构

点击查看笔记

三、网络编程三要素

1、IP

  • 设备在网络中的地址,是唯一的标识
  • 全称:Internet Protocol,是互联网协议地址,也称IP地址。是分配给上网设备的数字标签
  • 父类:IPV4IVP6

(1)IPV4

全称:Internet Protocal version 4,互联网通信协议第四版



(2)IPV6

全称:Internet Protocal version 6,互联网通信协议第六版



(3)特殊IP地址

127.0.0.1,也是localhost:是回送地址也称本地回环地址,也称本机IP,永远只会寻找当前所在的本机

(4)InetAddress类的使用

方法名称说明
static InetAddress getByName(String host)确认主机名称的IP地址。主机名称可以是机器名称,也可以是IP地址
String getHostName()获取此IP地址的主机名
String getHostAddress()返回文本显示中的IP地址字符串
java
InetAddress hdq = InetAddress.getByName("hdq");
System.out.println(hdq);            //hdq/192.168.1.198

String hostName = hdq.getHostName();
System.out.println(hostName);       //hdq

String hostAddress = hdq.getHostAddress();
System.out.println(hostAddress);    //192.168.1.198

2、端口号

  • 应用程序在设备中唯一的标识
  • 端口号:由两个字节表示的整数,取值范围:0~65535
  • 其中0~1023之间的端口号用于一些知名的网络服务或者应用,自己使用1024以上的端口就可以了
  • 一个端口号只能被一个应用程序使用

3、协议

  • 计算机网络中,连接和通信的规则被称为网络通信协议
  • 模型:
    1. OSI参考模型:世界互联协议标准,全球通信规范,但模型过于理想化,未能在因特网上进行广泛推广
    2. TCP/IP参考模型(或TCP/IP协议):事实上的国际标准

(1)UDP协议

  • 用户数据报协议(User Datagram protocol)
  • UDP是通信协议
  • 速度快,有大小限制一次最多发送64k,数据不安全,易丢失数据

(2)TCP协议

  • 传输控制协议TCP(Transmission Control Protocol)
  • TCP协议是的通信协议
  • 速度慢,没用大小限制,数据安全

四、UDP协议

1、发送数据

java
//创建DatagramSocket对象
DatagramSocket ds= new DatagramSocket();

String str="我真帅";
byte[] bytes=str.getBytes();
InetAddress address = InetAddress.getByName("hdq");
int port=10086;

//打包
DatagramPacket dp=new DatagramPacket(bytes,bytes.length,address,port);

//发送数据
ds.send(dp);

//释放资源
ds.close();

2、接收数据

java
//创建DatagramSocket对象,绑定发送数据的端口
DatagramSocket ds=new DatagramSocket(10086);

//接收数据的容器
byte[] bytes =new byte[1024];
DatagramPacket dp=new DatagramPacket(bytes,bytes.length);
ds.receive(dp);		//此处会阻塞,等待数据接收

//解析数据包
byte[] data=dp.getData();
int len=dp.getLength();
InetAddress address=dp.getAddress();
int port=dp.getPort();

System.out.println("接收到的数据是"+new String(data,0,len));
System.out.println("该数据是从"+address+"这台电脑中的"+port+"端口发送的");

//释放资源
ds.close();

3、三种通信方式

  1. 单播:使用DatagramSocket
  2. 组播:使用MulticastSocket
  3. 广播:使用DatagramSocket

(1)单播

之前的代码就是单播

(2)组播

  • 发送端

    java
    MulticastSocket ms=new MulticastSocket();
    
    //......
    
    InetAddress address = InetAddress.getByName("224.0.0.1");   //组播地址
    
    //......
  • 接收端

    java
    MulticastSocket ms=new MulticastSocket(10000);
    
    //......
    
    InetAddress address = InetAddress.getByName("224.0.0.1");   //组播地址
    ms.joinGroup(address);
    
    //......

(3)广播

和单播几乎一模一样,只需要改变

java
InetAddress address = InetAddress.getByName("255.255.255.255");

五、TCP协议

1、通信流程

  • 客户端

    1. 创建客户端的Socket对象(Socket)与指定服务端连接

      java
      Socket(String host , int port)
    2. 获取输出流,写数据

      java
      OutputStream getOutputStream()
    3. 释放资源

      java
      void close()
  • 服务器

    1. 创建客户端的Socket对象(ServerSocket)

      java
      ServerSocket(int port)
    2. 监听客户端连接,返回一个Socket对象

      java
      Socket accept()
    3. 获取输入流,读数据,并把数据显示在控制台

      java
      InputStream getInputStream()
    4. 释放资源

      java
      void close()

2、发送数据

java
//创建Socket对象
Socket socket=new Socket("192.168.1.198",5050);

//socket对象获取输出流
OutputStream os = socket.getOutputStream();
  
//写出数据
os.write("dsjids".getBytes());
 
//释放资源
os.close();
socket.close();

3、接受数据

java
//创建ServerSocket对象
ServerSocket ss=new ServerSocket(5050);
  
//监听客户端的链接
Socket socket=ss.accept();
  
//从连接通道获取输入流读取数据
InputStream is=socket.getInputStream();
//转换流
InputStreamReader isr=new InputStreamReader(is);
//缓冲流提高效率
BufferedReader br=new BufferedReader(isr);

int b;
while ((b=br.read())!=-1){
   System.out.println((char) b);
}

socket.close();
ss.close();

4、三次握手和四次挥手


(1)三次握手

保持建立连接

(4)四次挥手

确保连接断开,且数据处理完毕

六、TCP通信练习

1、多发多收

  • 客户端:多次发送数据
  • 服务端:接收多次接收数据,并打印

Client

java
package a10.a1;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class Client {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("192.168.1.198", 5001);
        OutputStream os = socket.getOutputStream();
        Scanner sc = new Scanner(System.in);

        int i = 0;
        while (true) {
            if (i == 5) break;
            i++;
            System.out.println("请输入你要发送的信息:");
            String message = sc.nextLine();
            os.write(message.getBytes());
        }
        socket.close();
    }
}

Server

java
package a10.a1;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(5001);

        Socket socket = ss.accept();

        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));

        int b;
        while ((b = br.read()) != -1) {
            System.out.println((char) b);
        }
        socket.close();
        ss.close();
    }
}

2、接收和反馈

  • 客户端:发送一条数据,接收服务端反馈的消息并打印
  • 服务器:接收数据并打印,再给客户端反馈消息

Client

java
package a10.a2;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;

public class Client {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("192.168.1.198", 5001);
        OutputStream os = socket.getOutputStream();

        String str = "呼叫服务端,收到请回答!!!";
        os.write(str.getBytes());

        socket.shutdownOutput();

        InputStreamReader isr = new InputStreamReader(socket.getInputStream());

        int b;
        while ((b = isr.read()) != -1) {
            System.out.print((char) b);
        }

        socket.close();
    }
}

Server

java
package a10.a2;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(5001);
        Socket socket = ss.accept();
        InputStreamReader isr = new InputStreamReader(socket.getInputStream());

        int b;
        while ((b = isr.read()) != -1) {
            System.out.print((char) b);
        }

        OutputStream os = socket.getOutputStream();
        String str = "服务端收到!!!";
        os.write(str.getBytes());

        socket.close();
        ss.close();
    }
}

3、上传文件

(1)字节流方式处理

Client

java
package a10.a3;

import java.io.*;
import java.net.Socket;
import java.nio.charset.Charset;

public class Client {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("192.168.1.198", 5001);

//        读取本地文件 --采用字节缓冲输入流
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("caogao\\huang.txt"));
//        使用字节缓冲输出流对外输出数据
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());

        byte[] bytes = new byte[1024];
        int len;
        while ((len = bis.read(bytes)) != -1) {
            bos.write(bytes, 0, len);
        }
        //刷新此缓冲的输出流
        bos.flush();

        socket.shutdownOutput();
        
//      接收服务器的回写数据
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String line = br.readLine();
        System.out.println(line);

//        释放资源
        socket.close();
    }
}

Server

java
package a10.a3;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.Charset;

public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(5001);

        Socket socket = ss.accept();

        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("caogao\\huang1.txt"));

        int len;
        byte[] bytes = new byte[1024];
        while ((len = bis.read(bytes)) != -1) {
            bos.write(bytes, 0, len);
        }
        bos.close();

        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        bw.write("上传成功");
        bw.newLine();
        bw.flush();

        socket.close();
        ss.close();
    }
}

(2)字符流方式处理

Client

java
package a10.a4;

import java.io.*;
import java.net.Socket;

public class Client {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("192.168.1.198", 5001);

//        读取本地文件 --采用字符缓冲输入流
        BufferedReader br = new BufferedReader(new FileReader("caogao\\huang.txt"));
//        使用字符缓冲输出流对外输出数据
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));

        String line;
        while ((line = br.readLine()) != null) {
            bw.write(line);
            bw.newLine();
        }

        bw.flush();
        br.close();

        socket.shutdownOutput();

//       接收服务器的回写数据
        BufferedReader br2 = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String message = br2.readLine();
        System.out.println(message);
        br2.close();

//        释放资源
        socket.close();
    }
}

Server

java
package a10.a4;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(5001);

        Socket socket = ss.accept();

        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        BufferedWriter bw = new BufferedWriter(new FileWriter("caogao\\huang1.txt"));

        String line;
        while ((line = br.readLine()) != null) {
            bw.write(line);
            bw.newLine();
        }
        bw.flush();
        bw.close();

//        回写
        BufferedWriter message = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        message.write("上传成功");
        message.newLine();
        message.flush();
        message.close();

        br.close();
        socket.close();
        ss.close();
    }
}

(3)多线程上传文件(频繁创建线程)

Client

java
package a10.a5;

import java.io.*;
import java.net.Socket;

public class Client {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("192.168.1.198", 5001);

//        读取本地文件 --采用字节缓冲输入流
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("caogao\\mate60.png"));
//        使用字节缓冲输出流对外输出数据
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());

        byte[] bytes = new byte[1024];
        int len;
        while ((len = bis.read(bytes)) != -1) {
            bos.write(bytes, 0, len);
        }
        bos.flush();

        socket.shutdownOutput();
//
////        接收服务器的回写数据
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String line = br.readLine();
        System.out.println(line);

//        释放资源
        socket.close();
    }
}

MyRunnable

java
package a10.a5;

import java.io.*;
import java.net.Socket;
import java.util.UUID;

public class MyRunnable implements Runnable {
    private Socket socket;

    public MyRunnable(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
            String name = UUID.randomUUID().toString().replace("-", "");
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("caogao\\" + name + ".png"));

            int len;
            byte[] bytes = new byte[1024];
            while ((len = bis.read(bytes)) != -1) {
                bos.write(bytes, 0, len);
            }
            bos.close();

            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            bw.write("上传成功");
            bw.newLine();
            bw.flush();

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

Server

java
package a10.a5;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(5001);

        while (true) {
            Socket socket = ss.accept();
//           开启线程
            new Thread(new MyRunnable(socket)).start();
        }
    }
}

(4)多线程上传文件(线程池)

代码只需修改Server类

java
package a10.a5;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;

public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(5001);

        ThreadPoolExecutor pool =new ThreadPoolExecutor(
                3,
                16,
                60,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(2),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy()
        );

        while (true) {
            Socket socket = ss.accept();
//           开启线程
            pool.submit(new MyRunnable(socket));
        }
    }
}