回顾总结17

网络

java.net包下提供了一系列的类或接口,供程序员使用,完成网络通信

IP

标识网络上设备的身份

域名

是为了方便记忆,解决记ip的困难

比如www.baidu.com,它的ip地址是110.242.68.3

相当于www.baidu.com引用了ip地址,

端口号

用于标识计算机上某个特定的网络程序

使用两个字节表示,范围有0 - 65535;其中0-1024被固定网络程序占用了

常见网络程序端口号

  • tomcat:8080
  • mysql:3306
  • oracle:1521
  • sqlserver:1433

网络通信协议

协议就是数据的组织形式(封装)

TCP/IP协议

Transmission Control Protocol:传输控制协议

Internet Protocol:因特网互联协议

tcp/ip:网络通讯协议

OSI模型


原本是七层,但是太细了,现在用的是四层

OSI模型 TCP/IP模型 对应协议
应用层
表示层 应用层 HTTP、DNS、telnet、ftp...
会话层
传输层 传输层(TCP) TCP、UDP...
网络层 网络层(IP) IP、ICMP、ARP...
数据链路层
物理层 物理+数据链路层 Link

TCP协议

传输控制协议

  1. 使用TCP协议前,需要建立TCP连接,形成传输数据通道
  2. 传输前,采用"三次握手"方式,并且是可靠传输
  3. TCP协议进行通信的两个应用进程:客户端、服务端
  4. 在连接中可进行大数据量的传输(可靠性)
  5. 传输后,采用"四次挥手"方式,可靠传输
  6. 传输完毕,需要释放已建立的连接。效率低,TCP连接同时只能连接一个

UDP协议

用户数据协议

  1. 将数据、源地址、目的地址封装成数据包,不需要建立连接
  2. 每个数据报的大小限制在64K内,不适合传输大量数据
  3. 因无需连接,故是不可靠的
  4. 发送数据结束时无需释放资源(因为不需要连接)速度快

InetAddress类

获取本机信息(主机名和ip)

通过域名获取远程服务器的ip

常用方法

  1. getLocalHost:获取本机InetAddress对象,会返回主机名(本机名称)和ip地址
  2. getByName:根据指定主机名/域名获取ip地址对象
  3. getHostName:获取InetAddress对象的主机名
  4. getHostAddress:获取InetAddress对象的地址

TCP网络通信编程

是端口对端口之间的网络通信

服务器端是可以指定的

客户端是TCP协议随机分配的

字节传输单向

服务器端

public class ServeSocket_ {
    public static void main(String[] args) throws IOException {
        //声明一个byte数组用来读取传送过来的数据
        byte[] bytes = new byte[1024];
        //定义一个int型数据,记录数组长度
        int len = 0;
        //服务器端,new一个ServerSocket,监听9999端口
        ServerSocket serverSocket = new ServerSocket(9999);
        //ServerSocket等待客户端消息,创建Socket
        Socket socket = serverSocket.accept();
        //使用输入流接收客户端信息
        InputStream inputStream = socket.getInputStream();
        //如果输入流里面还有数据就读取
        while ((len = inputStream.read(bytes)) != -1){
            //读取bytes数组里的数据,从0到len位置的
            System.out.println(new String(bytes,0,len));
        }
        //关闭流和socket,还有ServerSocket
        inputStream.close();
        socket.close();
        serverSocket.close();
    }
}

客户端

public class ClientSocket_ {
    public static void main(String[] args) throws IOException {
        //new一个Socket,需要连接的ip地址,和端口号
        Socket socket = new Socket(InetAddress.getLocalHost(),9999);
        //连接上了之后,获取输出流
        OutputStream outputStream = socket.getOutputStream();
        //用输出流写入数据
        outputStream.write("hello,java".getBytes(StandardCharsets.UTF_8));
        //关闭流,关闭socket
        outputStream.close();
        socket.close();
    }
}

字节传输双向

服务器端

public class Socket_2Server {
    public static void main(String[] args) throws IOException {
        //声明一个byte数组用来读取传送过来的数据
        byte[] bytes = new byte[1024];
        //定义一个int型数据,记录数组长度
        int len = 0;
        //服务器端,new一个ServerSocket,监听9999端口
        ServerSocket serverSocket = new ServerSocket(9999);
        //ServerSocket等待客户端消息,创建Socket
        Socket socket = serverSocket.accept();
        //使用输入流接收客户端信息
        InputStream inputStream = socket.getInputStream();
        //如果输入流里面还有数据就读取
        while ((len = inputStream.read(bytes)) != -1){
            //读取bytes数组里的数据,从0到len位置的
            System.out.println(new String(bytes,0,len));
        }
        //读取完之后,获取输出流
        OutputStream outputStream = socket.getOutputStream();
        //写入数据
        outputStream.write("hello,client".getBytes());
        //写完了,记得通知对面停止流的使用
        socket.shutdownOutput();
        //关闭流和socket,还有ServerSocket
        outputStream.close();
        inputStream.close();
        socket.close();
        serverSocket.close();
    }
}

客户端

public class Socket_2Client {
    public static void main(String[] args) throws IOException {
        //new一个Socket,需要连接的ip地址,和端口号
        Socket socket = new Socket(InetAddress.getLocalHost(),9999);
        //连接上了之后,获取输出流
        OutputStream outputStream = socket.getOutputStream();
        //用输出流写入数据
        outputStream.write("hello,server".getBytes());
        //写完之后,通知对面停止输出流的使用
        socket.shutdownOutput();
        //获取输入流
        InputStream inputStream = socket.getInputStream();
        int len = 0;
        byte[] bytes = new byte[1024];
        //读取数据
        while ((len = inputStream.read(bytes)) != -1){
            System.out.println(new String(bytes,0,len));
        }
        //关闭流,关闭socket
        inputStream.close();
        outputStream.close();
        socket.close();
    }
}

字符传输双向

服务器端

public class Socket_3Server {
    public static void main(String[] args) throws IOException {
        //声明一个字符串用来接收每行的数据
        String str = "";
        //服务器端,new一个ServerSocket,监听9999端口
        ServerSocket serverSocket = new ServerSocket(9999);
        //ServerSocket等待客户端消息,创建Socket
        Socket socket = serverSocket.accept();
        //使用输入流接收客户端信息
        InputStream inputStream = socket.getInputStream();
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        //读取一行数据
        str = bufferedReader.readLine();
        System.out.println(str);
        //读取完之后,获取输出流
        OutputStream outputStream = socket.getOutputStream();
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
        BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
        //写入数据
        bufferedWriter.write("hello,client");
        //写完了,使用newLine作为改行的结束符,通知对面该行结束,然后把数据刷进去
        bufferedWriter.newLine();
        bufferedWriter.flush();
        //关闭流和socket,还有ServerSocket
        bufferedWriter.close();
        bufferedReader.close();
        socket.close();
        serverSocket.close();
    }
}

客户端

public class Socket_3Client {
    public static void main(String[] args) throws IOException {
        //new一个Socket,需要连接的ip地址,和端口号
        Socket socket = new Socket(InetAddress.getLocalHost(),9999);
        //连接上了之后,获取输出流
        OutputStream outputStream = socket.getOutputStream();
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
        BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
        //用输出流写入数据
        bufferedWriter.write("hello,server");
        //写完之后,使用newLine结束该行,通知对面,然后把数据刷过去
        bufferedWriter.newLine();//字符流结束使用newLine时,输入流需要使用readLine
        bufferedWriter.flush();
        //获取输入流
        InputStream inputStream = socket.getInputStream();
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        
        String str = "";
        //读取数据
        str = bufferedReader.readLine();
        System.out.println(str);
        //关闭流,关闭socket
        bufferedReader.close();
        bufferedWriter.close();
        socket.close();
    }
}

传输文件双向

服务器端

/**
 * 这是服务器端
 * 1.新建ServerSocket服务
 * 2.等待连接,新建Socket
 * 3.等待客户端传送图片
 * 4.保存到本机
 * 5.完成后,给客户端传送“收到图片”信息
 */
public class Server {
    public static void main(String[] args) throws IOException {
        //1.新建ServerSocket服务
        ServerSocket serverSocket = new ServerSocket(9999);
        //2.等待连接,新建Socket
        Socket socket = serverSocket.accept();
        //3.等待客户端传送图片
        BufferedInputStream bufferedInputStream = new BufferedInputStream(socket.getInputStream());
        //4.保存到本机
        String dest = "e:\\dva.jpg";
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(dest,true));
        byte[] bytes = new byte[1024];
        while((bufferedInputStream.read(bytes)) != -1){
            bufferedOutputStream.write(bytes);
            bufferedOutputStream.flush();
        }
        //5.完成后,给客户端传送“收到图片”信息
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        bufferedWriter.write("收到图片,OVER");
        bufferedWriter.newLine();
        bufferedWriter.flush();

        bufferedWriter.close();
        bufferedOutputStream.close();
        bufferedInputStream.close();
        socket.close();
        serverSocket.close();
    }
}

客户端

/**
 * 这是客户端
 * 1.连接服务器端
 * 2.从自己电脑上获取图片到程序里
 * 3.把图片,从该程序传输给服务器端
 * 4.等待服务器端传输“获取图片”信息
 * 5.把“获取图片”信息打印出来
 */
public class Client {
    public static void main(String[] args) throws IOException {
        //1.连接服务器端
        Socket socket = new Socket(InetAddress.getLocalHost(),9999);
        //2.从自己电脑上获取图片到程序里
        String src = "d:\\dva.jpg";
        BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(src));
        //3.把图片,从该程序传输给服务器端
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream());
        int len;
        byte[] bytes = new byte[1024];
        while ((len = bufferedInputStream.read(bytes)) != -1){
            bufferedOutputStream.write(bytes,0,len);
            bufferedOutputStream.flush();
        }
        socket.shutdownOutput();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String str;
        while ((str = (bufferedReader.readLine())) != null){
            System.out.print(str);
        }

        bufferedReader.close();
        bufferedOutputStream.close();
        bufferedInputStream.close();
        socket.close();
    }
}

netstat指令

netstat:可以查看TCP网络连接的情况和端口监听情况

netstat -an:可以查看TCP和UDP网络连接情况和端口监听情况

netstat - an | more:可以分页显示上述情况

netstat -anb:可以查看具体那个程序(需要管理员权限)

details

  1. Listening表示某个端口在监听
  2. 如果有一个外部程序(客户端)连接到该端口,就会显示一条连接信息
  3. 可以输入ctrl + c 退出当前netstat指令

UDP网络通信编程

  1. 类DatagramSocket和DatagramPacket[数据包/数据报]实现了基于UDP协议的网络程序
  2. UDP数据报通过数据报套接字DatagramSocket发送和接收,系统不保证UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达
  3. DatagramPacket对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号,以及接收端的IP地址和端口号
  4. UDP协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接收方的连接

通信流程

  1. 核心的两个类/对象DatagramSocket和DatagramPacket
  2. 建立发送端,接收端
  3. 发送数据前,建立数据包DatagramPacket对象
  4. 调用DatagramSocket的发送,接收方法
  5. 关闭DatagramSocket

通信单向

发送端

public class UDP_1Sender {
    public static void main(String[] args) throws IOException {
        //新建一个DatagramSocket数据包,准备在8888端口接收数据
        DatagramSocket socket = new DatagramSocket(8888);
        //将需要发送的数据,装包
        byte[] data = "hello,明天学Java~".getBytes();
        DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getByName("192.168.43.100"),9999);
        socket.send(packet);
        socket.close();
    }
}

接收端

public class UDP_1Receiver {
    public static void main(String[] args) throws IOException {
        //创建一个DatagramSocket
        DatagramSocket socket = new DatagramSocket(9999);
        //UDP协议,一个数据包最大是64K
        byte[] bytes = new byte[1024];
        //创建一个DatagramPacket对象,准备接收数据
        DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
        //调用接收方法,将通过网络传输的DatagramPacket对象接收下来
        socket.receive(packet);
        //获取到数据包,把packet进行拆包,取出数据并显示
        int length = packet.getLength();//获取数据长度
        byte[] data = packet.getData();
        System.out.println(new String(data,0,length));
        //关闭资源
        socket.close();
    }
}

通信双向

先发送端

public class UDP_2Sender {
    public static void main(String[] args) throws IOException {
        //新建一个DatagramSocket数据包,准备在8888端口接收数据
        DatagramSocket socket = new DatagramSocket(8888);
        //将需要发送的数据,装包
        byte[] data = "hello,明天学Java~".getBytes();
        DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getByName("192.168.43.100"),9999);
        socket.send(packet);

        //准备接收,获取一个包
        byte[] bytes = new byte[1024];
        //直接重新赋值,不声明新的变量了
        packet = new DatagramPacket(bytes,bytes.length);
        socket.receive(packet);
        data = packet.getData();
        int length = packet.getLength();
        System.out.println(new String(data,0,length));
        socket.close();
    }
}

先接收端

public class UDP_2Receiver {
    public static void main(String[] args) throws IOException {
        //创建一个DatagramSocket
        DatagramSocket socket = new DatagramSocket(9999);
        //UDP协议,一个数据包最大是64K
        byte[] bytes = new byte[1024];
        //创建一个DatagramPacket对象,准备接收数据
        DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
        //调用接收方法,将通过网络传输的DatagramPacket对象接收下来
        socket.receive(packet);
        //获取到数据包,把packet进行拆包,取出数据并显示
        int length = packet.getLength();//获取数据长度
        byte[] data = packet.getData();
        System.out.println(new String(data,0,length));

        //获取要发送的数据并装包
        bytes = "好的,明天见".getBytes();
        packet = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.43.100"),8888);
        socket.send(packet);
        //关闭资源
        socket.close();
    }
}
posted @ 2021-08-22 09:33  灰线  阅读(45)  评论(0)    收藏  举报