Administrator
发布于 2023-02-10 / 10 阅读
0
0

Java入门(十三)——网络编程

概述

计算机网络是通过传输介质、通信设施和网络通信协议,把分散在不同地点的计算机设备互连起来的,实现资源共享和数据传输的系统。网络编程就是编写程序使互联网的两个(或多个)设备(如计算机)之间进行数据传输。Java语言对网络编程提供了良好的支持。通过其提供的接口我们可以很方便地进行网络编程。

简单的说,网络编程的目的就是直接或间接地通过网络协议与其他计算机实现数据交换,进行通讯。

网络通信模式

CS模式(Client---客户端,Server---服务端) 

CS即Client/Server(客户端/服务器)结构,最大的分别就是电脑上需要安装一个指定的软件客户端程序,通过这个程序访问软件(如腾讯视频应用 qq音乐应用等)

BS模式(Browser---浏览器,Server---服务端)

BS即Browser/Server(浏览器/服务器)结构,就是只安装维护一个服务器(Server),而客户端选用浏览器(Browse)运行软件。(如通过浏览器在线访问腾讯视频 访问qq音乐)

两者比较


对象

硬件环境

客户端要 求

软件安装

升级和维护

安全性

C/S

用户固定,并且处于相同区域,要求拥有相同的操作系统。

客户端的计算机电脑配置要求较高。

每一个客户端都必须安装和配置软件.

C/S每一个客户端都要升级程序。可以采用自动升级。

一般面向相对固定的用户群,程序更加注重流程,它可以对权限进行多层次校验,提供了更安全的存取模式,对信息安全的控制能力很强。一般高度机密的信息系统采用C/S结构适宜。

B/S

要有操作系统和浏览器,与操作系统平台无关。

客户端的计算机电脑配置要求较低。

可以在任何地方进行操作而不用安装任何专门的软件。

不必安装及维护

 

网络体系结构

世界上第一个网络体系结构由IBM公司提出(1974年,SNA),以后其他公司也相继提出自己的网络体系结构。为了促进计算机网络的发展,国际标准化组织ISO在现有网络的基础上,提出了不基于具体机型、操作系统或公司的网络体系结构,称为开放系统互连参考模型,即OSI/RM(Open System Interconnection Reference Model)。

ISO制定的OSI参考模型过于庞大、复杂招致了许多批评。与此相对,美国国防部提出了TCP/IP协议栈参考模型,简化了OSI参考模型,由于TCP/IP协议栈的简单,获得了广泛的应用,并成为后续因特网使用的参考模型。

OSI参考模型

OSI模型把网络通信的工作分为7层,分别是物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。

TCP/IP参考模型

IP(Internet Protocol)协议,又称为互联网协议,它能提供网间联接的完善功能,与IP放在一起的还有TCP(Transmission Control Protocol),即传输控制协议,它规定一种可靠的数据信息传递服务TCP与IP是在同一时期作为协议来设计的,功能互补,所以常统称为TCP/IP,是事实上的国际标准。

TCP/IP,即Transmission Control Protocol/Internet Protocol的简写,中译名为传输控制协议/因特网互联协议,是Internet最基本的协议,Internet国际互联网络的基础。

TCP/IP协议是一个开放的网络协议簇,它的名字主要取自最重要的网络层IP协议和传输层TCP协议。TCP/IP协议定义了电子设备如何连入因特网,以及数据如何在它们之间传输的标准。TCP/IP参考模型采用4层的层级结构,每一层都呼叫它的下一层所提供的协议来完成自己的需求,这4个层次分别是:网络接口层、网络层(IP层)、传输层(TCP层)、应用层。

网络协议

IP协议(Internet protocol)

IP协议的作用在于把各种数据包准备无误的传递给对方,其中两个重要的条件是IP地址和MAC地址。由于IP地址是稀有资源,不可能每个人都拥有一个IP地址,所以我们通常的IP地址是路由器给我们生成的IP地址,路由器里面会记录我们的MAC地址。而MAC地址是全球唯一的。举例,IP地址就如同是我们居住小区的地址,而MAC地址就是我们住的那栋楼那个房间那个人。IP地址采用的IPv4格式,目前正在向IPv6过渡。

TCP协议(Transmission Control Protocol)

TCP(传输控制协议)是面向连接的传输层协议。TCP层是位于IP层之上,应用层之下的中间层。不同主机的应用层之间经常需要可靠的、像管道一样的连接,但是IP层不提供这样的流机制,而是提供不可靠的包交换。TCP协议采用字节流传输数据。

UDP协议(User Datagram Protocol)

UDP,用户数据报协议,它是TCP/IP协议簇中无连接的运输层协议。它提供了应用程序之间要发送数据的数据报。由于UDP缺乏可靠性且属于无连接协议,所以应用程序通常必须容许一些丢失、错误或重复的数据包。

TCP与UDP的区别

  1. TCP基于连接,UDP是无连接的;
  2. 对系统资源的要求,TCP较多,UDP较少;
  3. UDP程序结构较简单;
  4. TCP是流模式,而UDP是数据报模式;
  5. TCP保证数据正确性,而UDP可能丢包;TCP保证数据顺序,而UDP不保证;

HTTP协议(Hypertext Transfer Protocol)

HTTP,超文本传输协议,它是互联网上应用最为广泛的一种网络协议。HTTP是一种应用层协议,它是基于TCP协议之上的请求/响应式的协议。HTTP协议是Web浏览器和Web服务器之间通信的标准协议。HTTP指定客户端与服务器如何建立连接、客户端如何从服务器请求数据,服务器如何响应请求,以及最后如何关闭连接。HTTP连接使用TCP/IP来传输数据。

网络编程要素

IP地址

想让⽹络中的计算机能够互相通信,必须为每台计算机指定⼀个标识号,通过这个标识号来指定要接收数据的计算机和识别发送的计算机,而IP地址就是这个标识号。也就是设备的标识 。

端口

⽹络的通信,本质上是两个应⽤程序的通信。每台计算机都有很多应⽤程序,那么在⽹络通信时,如何区分这些应⽤程序呢?如果说IP地址可以唯⼀表⽰⽹络中的设备,那么端口号就可以唯⼀标识设备中的应⽤程序了。也就是应⽤程序的标识
⽤两个字节表⽰的整数,它的取值范围是0-65535。其中,0-1023之间的端口号⽤于⼀些知名的⽹络服务和应⽤,普通的应⽤程序需要使⽤1024以上的端口号。如果端口号被另外⼀个服务或应⽤所占⽤,会导致当前程序启动失败。

协议

通过计算机⽹络可以使多台计算机实现连接,位于同⼀个⽹络中的计算机在进⾏连接和通信时需要遵守⼀定的规则,这就好⽐在道路中⾏驶的骑⻋⼀定要遵守交通规则⼀样。在计算机⽹络中,这些连接和通信的规则被称为⽹络通信协议,它对数据的传输格式、传输速率、传输步骤等做了统⼀规定,通信双⽅必须同时遵守才能完成数据交换。常⻅的协议有UDP协议和TCP协议。

Socket编程

socket概述

Socket通常称为套接字,⽤于应⽤程序之间建⽴远程连接,Socket内部通TCP/IP协议进⾏数据传输,可以简单的理解为对IP地址和端口号的描述。Socket接口是由计算机操作系统提供的,编程语⾔提供对Socket接口调⽤的封装。通常计算机同时运⾏多个应⽤程序,仅仅有IP地址是⽆法确定由哪个应⽤程序接收数据,所以操作系统抽象出Socket接口,每个应⽤程序对应不同的socket(每个⽹络应⽤程序分配不同的端口号)。

Socket编程需要实现服务器端和客⼾端,因为这两个设备通讯时,需要知道对⽅的IP和端口号。通常服务器端有个固定的端口号,客⼾端直接通过服务器的IP地址和端口号进⾏访问服务器端,同时告知客⼾端的端口号,于是他们之间就可以通过socket进⾏通信。

ServerSocket 类的方法

服务器应用程序通过使用 java.net.ServerSocket 类以获取一个端口,并且侦听客户端请求。

ServerSocket 类有四个构造方法:

序号 方法描述
1 public ServerSocket(int port) throws IOException
创建绑定到特定端口的服务器套接字。
2 public ServerSocket(int port, int backlog) throws IOException
利用指定的 backlog 创建服务器套接字并将其绑定到指定的本地端口号。
3 public ServerSocket(int port, int backlog, InetAddress address) throws IOException
使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。
4 public ServerSocket() throws IOException
创建非绑定服务器套接字。

创建非绑定服务器套接字。 如果 ServerSocket 构造方法没有抛出异常,就意味着你的应用程序已经成功绑定到指定的端口,并且侦听客户端请求。

这里有一些 ServerSocket 类的常用方法:

序号 方法描述
1 public int getLocalPort()
  返回此套接字在其上侦听的端口。
2 public Socket accept() throws IOException
侦听并接受到此套接字的连接。
3 public void setSoTimeout(int timeout)
 通过指定超时值启用/禁用 SO_TIMEOUT,以毫秒为单位。
4 public void bind(SocketAddress host, int backlog)
将 ServerSocket 绑定到特定地址(IP 地址和端口号)。

Socket 类的方法

java.net.Socket 类代表客户端和服务器都用来互相沟通的套接字。客户端要获取一个 Socket 对象通过实例化 ,而 服务器获得一个 Socket 对象则通过 accept() 方法的返回值。

Socket 类有五个构造方法.

序号 方法描述
1 public Socket(String host, int port) throws UnknownHostException, IOException.
创建一个流套接字并将其连接到指定主机上的指定端口号。
2 public Socket(InetAddress host, int port) throws IOException
创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
3 public Socket(String host, int port, InetAddress localAddress, int localPort) throws IOException.
创建一个套接字并将其连接到指定远程主机上的指定远程端口。
4 public Socket(InetAddress host, int port, InetAddress localAddress, int localPort) throws IOException.
创建一个套接字并将其连接到指定远程地址上的指定远程端口。
5 public Socket()
通过系统默认类型的 SocketImpl 创建未连接套接字

当 Socket 构造方法返回,并没有简单的实例化了一个 Socket 对象,它实际上会尝试连接到指定的服务器和端口。

下面列出了一些感兴趣的方法,注意客户端和服务器端都有一个 Socket 对象,所以无论客户端还是服务端都能够调用这些方法。

序号 方法描述
1 public void connect(SocketAddress host, int timeout) throws IOException
将此套接字连接到服务器,并指定一个超时值。
2 public InetAddress getInetAddress()
 返回套接字连接的地址。
3 public int getPort()
返回此套接字连接到的远程端口。
4 public int getLocalPort()
返回此套接字绑定到的本地端口。
5 public SocketAddress getRemoteSocketAddress()
返回此套接字连接的端点的地址,如果未连接则返回 null。
6 public InputStream getInputStream() throws IOException
返回此套接字的输入流。
7 public OutputStream getOutputStream() throws IOException
返回此套接字的输出流。
8 public void close() throws IOException
关闭此套接字。

InetAddress 类的方法

这个类表示互联网协议(IP)地址。下面列出了 Socket 编程时比较有用的方法:

序号 方法描述
1 static InetAddress getByAddress(byte[] addr)
在给定原始 IP 地址的情况下,返回 InetAddress 对象。
2 static InetAddress getByAddress(String host, byte[] addr)
根据提供的主机名和 IP 地址创建 InetAddress。
3 static InetAddress getByName(String host)
在给定主机名的情况下确定主机的 IP 地址。
4 String getHostAddress() 
返回 IP 地址字符串(以文本表现形式)。
5 String getHostName() 
 获取此 IP 地址的主机名。
6 static InetAddress getLocalHost()
返回本地主机。
7 String toString()
将此 IP 地址转换为 String。

TCP网络编程

案例:客户端发送消息给服务端,服务端输出消息到控制台

//客户端
public class TcpClientDemo {
    public static void main(String[] args) {
        Socket socket = null;
        OutputStream os = null;
        try {
            //1. 连接服务器的地址
            InetAddress ipAddr = InetAddress.getByName("127.0.0.1");
            int port = 7788;
            //2. 创建一个Socket
            socket = new Socket(ipAddr, port);
            //3. 创建一个输出流
            os = socket.getOutputStream();
            os.write("今天不气不错,你觉得呢".getBytes());
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4. 关闭资源
            try {
                if (os != null) {
                    os.close();
                }
                if (socket != null) {
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

//服务端
public class TcpServerDemo {
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        Socket socket = null;
        InputStream is = null;
        ByteArrayOutputStream baos = null;
        try {
            //1. 开放服务器端口,创建ServerSocket
            serverSocket = new ServerSocket(7788);
            //2. 等待客户端的连接
            socket = serverSocket.accept();
            //3. 读取客户端的消息
            is = socket.getInputStream();
//            可能存在中文乱码
//            byte[] buffer = new byte[1024];
//            int len;
//            while ((len = is.read(buffer)) != -1) {
//                String str = new String(buffer, 0, len);
//                System.out.println(str);
//            }

            baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len;
            while ((len = is.read(buffer)) != -1) {
                baos.write(buffer, 0, len);
            }
            System.out.println(baos.toString());
            System.out.println("数据来源地址:" + socket.getInetAddress().getHostName());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4. 关闭资源
            try {
                if (baos != null) {
                    baos.close();
                }
                if (is != null) {
                    is.close();
                }
                if (socket != null) {
                    socket.close();
                }
                if (serverSocket != null) {
                    serverSocket.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

输出结果

今天不气不错,你觉得呢
数据来源地址:ieonline.Microsoft.com

UDP网络编程

注意点:

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

聊天室代码示例

//发送端
public class TalkSend implements Runnable {
    private DatagramSocket socket;
    private BufferedReader br;
    private String toIP;
    private int toPort;

    public TalkSend(int port, String toIP, int toPort) {
        this.toIP = toIP;
        this.toPort = toPort;
        try {
            socket = new DatagramSocket(port);
            br = new BufferedReader(new InputStreamReader(System.in));
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        while (true) {
            try {
                String data = br.readLine();
                byte[] datas = data.getBytes();
                //3. 封装成DatagramPacket包裹,需要指定目的地
                DatagramPacket packet = new
                        DatagramPacket(datas, 0, datas.length,
                        new InetSocketAddress(this.toIP, this.toPort));
                //4. 发送包裹send
                socket.send(packet);
                //退出判断
                if (data.equals("bye")) {
                    break;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //5. 释放资源
        socket.close();
    }
}

//接收端
public class TalkReceive implements Runnable {
    private DatagramSocket socket;
    private String msgFrom;

    public TalkReceive(int port, String msgFrom) {
        this.msgFrom = msgFrom;
        try {
            socket = new DatagramSocket(port);
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        while (true) {
            try {
                //准备接收包裹;
                byte[] container = new byte[1024];
                DatagramPacket packet = new DatagramPacket(container, 0,
                        container.length);
                socket.receive(packet); //阻塞式接收包裹
                byte[] datas = packet.getData();
                int len = packet.getLength();
                String data = new String(datas, 0, len);
                System.out.println(msgFrom + ":" + data);
                //退出判断
                if (data.equals("bye")) {
                    break;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        socket.close();
    }
}

public class TalkTeacher {
    public static void main(String[] args) {
        new Thread(new TalkSend(8888, "localhost", 6666)).start();
        new Thread(new TalkReceive(9999, "学生")).start();
    }
}

public class TalkStudent {
    public static void main(String[] args) {
        new Thread(new TalkSend(5555, "localhost", 9999)).start();
        new Thread(new TalkReceive(6666, "老师")).start();
    }
}

输出结果

//学生端
你好,在吗
老师:在的,请问有什么事
培训课多少钱一期
老师:9800
这么贵?不要了
老师:再看看嘛
bye
老师:bye

//老师端
学生:你好,在吗
在的,请问有什么事
学生:培训课多少钱一期
9800
学生:这么贵?不要了
再看看嘛
学生:bye
bye

URL编程

URL:是统一资源定位器的简称,它表示Internet某一资源的地址。通过URL我们可以访问Internet上的各种网络资源,比如最常见的www,ftp站点。浏览器通过解析给定的URL可以在网络上查找相应的文件或其他资源。

组成:URL的基本结构由5部分组成。<传输协议>://<主机名>:<端口号>/<文件名>#<引用>

属性方法

  • getFile():获得URL指定资源的完整文件名。
  • getHost():返回主机名。
  • getPath():返回指定资源的文件目录和文件名。
  • getPort():返回端口号。
  • getProtocol():返回表示URL中协议的字符串对象。
  • getRef():返回URL中的HTML文档标记,即#号标记。
  • getUserInfo():返回用户信息。

URL有两种方法可以用来访问Interent上资源。

  1. 使用URL的openConnection()方法创建一个URLConnection类的对象。再通过URLConnection对象获取相应的输入/输出流。
  2. 利用URL类的openStream()方法。openStream()方法与指定的URL建立连接并返回InputStream类的对象。


评论