JAVA网络初始及网络编程

目录

一、网络初始

1、IP地址

2、端口号

3、协议

4、五元组

5、协议分层

6、封装和分用

二、网络编程

1、概念

2、API

3、TCP与UDP的区别

4、UDP的Socket API

5、TCP的Socket API


一、网络初始

1、IP地址

描述了一个设备在网络上的地址。32位,4个字节表示,使用三个点进行分隔。

例如:192.198.1.200;

2、端口号

区分主机上不同的应用程序,2个字节。0一般不使用,1-1023这个范围的端口号,知名端口号,留给一些比较常见的服务器程序进行应用的。

3、协议

一种约定,约定了通行双方按照什么样的方式传输数据。网络中,本质上通过光/电信号传输数据

4、五元组

一次通行过程中必不可少的信息:源端口、源IP、目的端口、目的IP、协议类型。

5、协议分层

如果一个协议过于庞大不好解决问题,可以把一个大的协议拆分成多个小的协议。更好的管理这些协议,就进行了协议分层。约定了不同层次之间的调用关系,上层协议调用下层协议,下层协议给上层协议提供支持。

好处:①协议分层之后,上层和下层彼此之间进行了封装,使用上层协议不必关注下层协议,使用下层协议不必关注上层协议;②每层协议可以根据需要灵活替换。

OSI七层网络协议:

TCP/IP五层网络协议(最主要的)

                       

(1)物理层:描述的是网络通信的硬件设备;比如:使用的网线、光纤应满足什么规格;

(2)数据链路层:两个相邻结点之间数据的传输情况,负责设备之间数据帧的传送和识别;

(3)网络层:进行路径规划,负责地址管理和路由选择;

(4)传输层:关注起点和终点,负责两个主机间数据传输;

(5)应用层:如何使用这个数据,负责应用程序间沟通。

物理层和数据链路层对应到设备驱动程序与网络接口;网络层和传输层对应到操作系统;应用层对应到应用程序。

对于一台主机,操作系统内核实现了从应用层到物理层,涉及到TCP/IP模型的5层;

对于一个路由器,实现了网络层到物理层,涉及到TCP/IP模型的下3层;

对于一个交换机(扩展路由器的端口),实现了数据链路层到物理层,涉及到TCP/IP模型的下2层;

对于集线器,只实现了物理层。

6、封装和分用

描述了网络通信过程中,基本的数据传输流程。

eg:用户A通过qq将hello发送给用户B

发送方:

(1)应用层

qq应用程序就会把用户A输入的hello打包成应用层的数据报(数据报的格式只有qq程序员知道)

假设为以下格式:

上述规则就为应用层的协议,由程序员制定的规则。具体用什么字段、字段顺序都可以灵活调整。

(2)传输层

对刚才应用层的数据报再进行打包转为传输层的数据报,本质上是字符串的拼接,拼接上传输层的报头。传输层有两种协议(UDP和TCP)

UDP报头:二进制数据,最关键的信息就是源端口和目的端口。

(3)网络层

对刚才传输层的数据报再进行打包转为网络层的数据报。网络层最主要的协议为IP协议

IP报头:最关键的信息为源IP和目的IP

(4)数据链路层

对刚才网络层的数据报再进行打包转为数据链路层的数据报。

以太网报头:最关键的信息为源mac地址和目的mac地址。

(5)物理层

把上述数据转为二进制,通过光/电信号进行传播。

数据发送成功后就会经过A和B之间的一系列交换机和路由器进行转发。当数据到达B之后,就会对数据进行“分用”(层层解析)。

接收方:

(1)物理层

拿到光/电信号,转化为二进制,得到以太网数据报,交给数据链路层的协议处理。

(2)数据链路层

针对以太网数据报,通过以太网协议解析出以太网数据报头、报尾、载荷,将载荷(IP数据报)交给网络层的协议处理。

(3)网络层

针对IP数据报,通过IP协议解析出IP报头和载荷,将载荷(UDP数据报)交给传输层的协议处理。

(4)传输层

针对UDP数据报,通过UDP协议解析出UDP报头和载荷,将载荷(应用层数据报)通过解析出的端口号交给qq程序。

(5)应用层

针对应用层数据报,根据应用层协议解析出内容,将内容显示在对应界面上。

二、网络编程

1、概念

网络上的主机,拥有不同的进程,通过编程,基于网络实现不同进程之间的网络通信(数据传输)

2、API

Socket API ,是由系统提供用于网络通信的技术,是基于TCP/UDP协议的。

3、TCP与UDP的区别

①TCP是有连接的,UDP是无连接的。(双方是非保存彼此关键信息)

②TCP是可靠传输,UDP是不可靠传输。(是否知道数据成功传输给接收方)

③TCP是面向字节流的,UDP是面向数据报的。

④TCP与UDP都是全双工的,允许双向通信。

4、UDP的Socket API

(1)DatagramSocket类:代表系统内部的Socket文件,对于文件有读数据和写数据,读数据相当于通过网卡接收数据,写数据相当于通过网卡发送数据。

receive()方法是接收数据(请求),未接收到请求时会阻塞等待;send()方法是发送数据(响应)。

在构造服务器时,程序员需要指定空闲的端口号,可控的。

在构造客户端时,不需要指定端口号,不可控,系统分配端口号。

(2)DatagramPacket类

代表数据报,UDP是面向数据报的,以数据报为基本单位传输。

(3)应用:写一个简单的Echo服务器/客户端,客户端发送请求之后,服务器响应一样的内容发送给客户端。

服务器:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class UdpEchoServe {
    DatagramSocket socket;
    public UdpEchoServe(int port) throws SocketException {
        socket=new DatagramSocket(port);  //指定端口号
    }
    public void start() throws IOException {
        System.out.println("服务器启动!!!");
        while (true){
            //1、接收请求
            DatagramPacket requestPacket=new DatagramPacket(new byte[4096],4096); //二进制形式存在数据报中
            socket.receive(requestPacket);
            String request=new String(requestPacket.getData(),0,requestPacket.getLength());
            //2、响应请求->Echo
            String response=process(request);
            //3、发送响应给客户端
            DatagramPacket responsePacket=new DatagramPacket(response.getBytes(),response.getBytes().length,
                    requestPacket.getSocketAddress());
            socket.send(responsePacket);
            //4、打印信息
            System.out.printf("[IP=%s:port=%d],request=%s,response=%s\n",requestPacket.getAddress().toString(),
                    requestPacket.getPort(),request,response);
        }
    }
    public String process(String request){
        return request;
    }

    public static void main(String[] args) throws IOException {
        UdpEchoServe serve=new UdpEchoServe(4090);
        serve.start();
    }
}

客户端:

import java.io.IOException;
import java.net.*;
import java.util.Scanner;

public class UdpEchoClient {
    private String ip;
    private int port;
    DatagramSocket socket;
    //记录对端的信息,不用指定客户端端口
    public UdpEchoClient(String ip,int port) throws SocketException {
        this.ip=ip;
        this.port=port;
        socket=new DatagramSocket();
    }
    public void start() throws IOException {
        System.out.println("客户端启动!!!");
        Scanner sc=new Scanner(System.in);
        while (true){
            //1、控制台写入请求
            System.out.print("->");
            String request=sc.next();
            //2、发送请求给客户端
            DatagramPacket requestPacket=new DatagramPacket(request.getBytes(),request.getBytes().length,
                    InetAddress.getByName(ip),port);
            socket.send(requestPacket);
            //3、接收响应
            DatagramPacket responsePacket=new DatagramPacket(new byte[4096],4096);
            socket.receive(responsePacket);
            //4、打印响应
            String response=new String(responsePacket.getData(),0,responsePacket.getLength());
            System.out.println(response);
        }
    }

    public static void main(String[] args) throws IOException {
        UdpEchoClient client=new UdpEchoClient("192.168.0.102",4090);
        client.start();
    }
}

注:UDP的DatagramSocket不需要释放资源,因为在程序中只有一个对象,贯穿整个程序,无需释放。

5、TCP的Socket API

(1)ServerSocket类:服务器使用的类,绑定端口号;

(2)Socket类:服务器或客户端使用的类;

(3)建立连接:客户端发起连接请求,内核完成建立连接的流程(三次握手)之后,就会在内核的队列(ServerSocket拥有的队列)中排队,服务器的应用程序通过accept()方法,取出连接对象。

(4)接收请求:inputStream;发送请求:OutputStream.

(5)考虑到有多个不同的客户端,线程池接收不同客户端和响应请求。

(6)应用:写一个简单的Echo服务器/客户端,客户端发送请求之后,服务器响应一样的内容发送给客户端。

服务器:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TcpEchoServer {
    ServerSocket serverSocket;
    public TcpEchoServer(int port) throws IOException {
        serverSocket=new ServerSocket(port);
    }
    public void start() throws IOException{
        System.out.println("服务器启动!!!");
        while (true){
            ExecutorService service= Executors.newCachedThreadPool();
            Socket clientSocket=serverSocket.accept(); //建立连接
            service.submit(new Runnable() {
                @Override
                public void run() {
                    //处理建立好的连接
                    try {
                        processConnection(clientSocket);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            });
        }
    }
    public void processConnection(Socket clientSocket) throws IOException {
        System.out.printf("[ip=%s:port=%d ,客户端上线!!!\n",clientSocket.getInetAddress(),clientSocket.getPort());
        try(InputStream inputStream=clientSocket.getInputStream();
            OutputStream outputStream=clientSocket.getOutputStream()) {
            while (true){
                Scanner sc=new Scanner(inputStream);
                //1、读取请求
                if(!sc.hasNext()){
                    System.out.printf("[ip=%s:port=%d ,客户端下线!!!\n",clientSocket.getInetAddress(),clientSocket.getPort());
                    break;
                }
                String request=sc.next();
                //2、响应请求
                String response=process(request);
                //3、发送响应给客户端
                PrintWriter writer=new PrintWriter(outputStream);
                writer.println(response);
                writer.flush();
                //4、打印信息
                System.out.printf("[%s:%d],req=%s,res=%s\n",clientSocket.getInetAddress(),clientSocket.getPort(),request,response);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            clientSocket.close();
        }
    }
    public String process(String request){
        return request;
    }

    public static void main(String[] args) throws IOException {
        TcpEchoServer server=new TcpEchoServer(4090);
        server.start();
    }
}

客户端:

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

public class TcpEchoClient {
    Socket clientSocket;

    public TcpEchoClient(String ip, int port) throws IOException {
        clientSocket = new Socket(ip, port); //三次握手建立连接
    }

    public void start() {
        System.out.println("客户端启动!!!");
        Scanner sc = new Scanner(System.in);
        try (InputStream inputStream=clientSocket.getInputStream();
             OutputStream outputStream=clientSocket.getOutputStream();
             PrintWriter writer=new PrintWriter(outputStream);
             Scanner sc1=new Scanner(inputStream);) {
            while (true) {
                //1、输入请求
                System.out.print("->");
                String request=sc.next();
                //2、发送请求
                writer.println(request);
                writer.flush();
                //3、接收响应
                String response=sc1.next();
                //4、打印响应
                System.out.println(response);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) throws IOException {
        TcpEchoClient client=new TcpEchoClient("192.168.0.102",4090);
        client.start();
    }
}

注:服务器中,每次执行可能会建立多个Socket对象,用完一个客户端就需释放资源。

  • 22
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ambition…

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值