10 - JavaSE之网络编程

网络编程

网络通信协议分层思想

为什么要分层呢?因为整个网络协议非常复杂,要涉及到方方面面的知识,而且还有对底层硬件的操作,利用分层的思想,我们可以将复杂的通信协议分割成一层层的形式,上一层可以调用下一层,而与再下一层不发生关系,各层之间互不影响,便于系统的开发。我们把用户程序作为最高层,把物理通信线路作为最底层,高层到底层一步步封装,我们不需要直接操作底层,而是操作最简单的最高层,这就是分层的意义。


参考模型

  1. OSI七层模型

物理层、数据链路层、网络层、传输层、会话层、表示层、应用层

  1. TCP/IP参考模型

应用层、传输层(TCP/UDP层)、网络层(IP层)、数据链路层、物理层

我们今天要讲的主要是传输层。


IP协议

IP层:给我们做的最大贡献就是提供了独一无二的IP地址。

IP TCP UDP 网关 内网 子网掩码

  • TCP
  1. TCP是Transfer Control Protocol(传输控制协议)的简称,是一种面向连接的保证可靠传输的协议。一个TCP连接必须要经过三次“对话”才能建立起来。
  2. 在TCP/IP协议中,IP层主要负责网络主机的定位,数据传输的路由,由IP地址可以唯一确定Internet上的一台主机。而TCP层则提供面向应用的可靠的或非可靠的数据传输机制,这是网络编程的主要对象,一般不需要关心IP层是如何处理数据的。
  3. 发送方和接收方的成对的两个socket之间必须建立连接,以便在TCP协议的基础上进行通信。当一个socket(通常都是serversocket)等待建立连接时,另一个socket可以要求进行连接,一旦这两个socket连接起来,它们就可以进行双向数据传输,双方都可以进行发送或接收操作。
  • UDP

UDP是User Datagram Protocol的简称,是一种无连接的协议。UDP是从一台计算机向另一台计算机发送称为数据报的独立数据包的协议,该协议并不保证数据报是否能正确地到达目的地,它是一个非面向连接的协议。每个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传往目的地,因此能否到达目的地,到达时间以及内容的正确性都是不能保证的。

  • TCP和UDP的比较
  1. 使用UDP时,每个数据报中都给出了完整的地址信息,因此无需建立发送方和接收方的连接。对于TCP协议,由于它是一个面向连接的协议,在socket之间进行数据传输之前必然要建立连接,所以在TCP中多了一个连接建立的时间。
  2. 使用UDP传输数据时是有大小限制的,每个被传输的数据报必须限定在64KB之内。TCP没有这方面的限制,一旦连接建立起来,双方的socket就可以按统一的格式传输大量的数据。
  3. UDP是一个不可靠的协议,发送方所发送的数据报并不一定以相同的次序到达接收方;TCP是一个可靠的协议,它确保接收方完全正确地获取发送方所发送的全部数据。
  4. 可靠的传输是要付出代价的,对数据内容正确性的检验必然占用计算机的处理时间和网络的带宽。因此TCP传输的效率不如UDP高。
  5. TCP在网路通信上有极强的生命力,例如远程连接(Telnet)和文件传输(FTP)都需要不定长度的数据被可靠地传输。相比之下UDP操作简单,而且仅需要较少的监护,因此通常用于局域网高可靠性的分散系统中client/server应用程序。
  • Socket
  1. 两个 Java 应用程序可以通过一个双向的网络通信连接实现数据交换,这个双向链路的一端称为一个Socket。
  2. Socket 通常用来实现 client-server 连接。
  3. java.net 包中定义的两个类 Socket 和 ServerSocket ,分别用来实现双向连接的 client 和 server 端。
  4. 建立连接时所需的寻址信息为远程计算机的 IP 地址和端口号(Port)

端口:用于区分不同的网络应用程序 ,占两个字节,所以共有 65535 个端口号。不过系统会随时征用 1024 以下端口。

端口又分TCP和UDP端口,各有 65535 个端口。


TCP Socket 通信模型

示例1:最简单的Socket模型:Client写数据务器读数据

// Server
import java.net.*;
import java.io.*;

public class Server {
    public static void main(String[] args) throws Exception {
        ServerSocket ss = new ServerSocket(6666); // 已经开始监听6666端口了      
        while(true) {
            Socket s = ss.accept(); // ss建立一个插座Socket,接受和客户端s的连接(阻塞式连接),连接成功,相当于服务器和客户端之间连接了两根管道。读的管道(InputStream)和写的管道(OutputStream)。
            System.out.println("A Client has Connected!");
            DataInputStream dis = new DataInputStream(s.getInputStream());
            System.out.println(dis.readUTF());// 所以先获取管道,要说就获取写的管道,要听就获取读的管道。
            dis.close();
            s.close();
        }
    }
}

// Client
import java.net.*;
import java.io.*;

public class Client {
    public static void main(String[] args) throws Exception {
        Socket s = new Socket("127.0.0.1", 6666);// 申请和ss建立连接   
        DataOutputStream dos = new DataOutputStream(s.getOutputStream());       
        dos.writeUTF("Hello TCP."); // 连接好之后开始说话,通过管道流的方式来说话,所以先获取管道,要说就获取写的管道,要听就获取读的管道。   
        dos.flush();
        dos.close();
        s.close();
    }
}

Client 端的 IP 地址不能随意指定,不知为何。

示例2:服务器向客户端发送数据,客户端接收数据

// Server
import java.net.*;
import java.io.*;

public class Server {
    public static void main(String[] args) {
        try {
            ServerSocket ss = new ServerSocket(6666);       
            while(true) {
                Socket s = ss.accept();
                System.out.println("A Client has Connected!");
                DataOutputStream dos = new DataOutputStream(s.getOutputStream());
                dos.writeUTF("Hi [#IP:" + s.getInetAddress() + " #Port:" + s.getPort() + "], I'm Server.");
                dos.close();
                s.close();
            }
        } catch (IOException e) {
            System.out.println("Server Error!!!");
            e.printStackTrace();
        }
    }
}

// Client
import java.net.*;
import java.io.*;

public class Client {
    public static void main(String[] args) {
        try {
            Socket s = new Socket("127.0.0.1", 6666);       
            DataInputStream dis = new DataInputStream(s.getInputStream());      
            System.out.println(dis.readUTF());  
            dis.close();
            s.close();
        } catch(IOException e) {
            System.out.println("Client Error!!!");
            e.printStackTrace();
        }
    }
}
//I:\Java\Demo>java Client
//Hi [#IP:/127.0.0.1 #Port:15944], I'm Server.

//I:\Java\Demo>java Client
//Hi [#IP:/127.0.0.1 #Port:15953], I'm Server.

//I:\Java\Demo>java Client
//Hi [#IP:/127.0.0.1 #Port:15954], I'm Server.

//I:\Java\Demo>java Client
//Hi [#IP:/127.0.0.1 #Port:15955], I'm Server.

示例3:服务器和客户端同时读写数据(当然一个先读一个先写喽,如果两个都读或都写的话就卡死啦)

// Server
// 服务器先接收客户端的数据,然后再发送数据给客户端
import java.net.*;
import java.io.*;

public class Server {
    public static void main(String[] args) {
        try {
            ServerSocket ss = new ServerSocket(6666);
            Socket s = ss.accept();
            
            System.out.println("A Client has Connected!");
            
            DataInputStream dis = new DataInputStream(s.getInputStream());
            DataOutputStream dos = new DataOutputStream(s.getOutputStream());
            
            String str = null;
            if((str=dis.readUTF()) != null)
            {
                System.out.println("I'm reseaving message...");
                Thread.sleep(3000);
                dos.writeUTF("Hi [#IP:" + s.getInetAddress() + " #Port:" + s.getPort() + "], I hava reseaved: " + str);
            }
            
            dis.close();
            dos.close();
            s.close();
        } catch (IOException e) {
            System.out.println("Server Error!!!");
            e.printStackTrace();
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


// Client
// 客户端先发送数据给服务器,再接收服务器的回复。
import java.net.*;
import java.io.*;

public class Client {
    public static void main(String[] args) {
        try {
            Socket s = new Socket("localhost", 6666);
            
            DataInputStream dis = new DataInputStream(s.getInputStream());
            DataOutputStream dos = new DataOutputStream(s.getOutputStream());
            
            System.out.println("Hi Server, I'm sending message to you...");
            
            Thread.sleep(2000);
            
            dos.writeUTF("Hello HYJ.");
            System.out.println(dis.readUTF());
            
            dis.close();
            s.close();
        } catch(UnknownHostException e) {
            e.printStackTrace();
        } catch(IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

注意:这里面使用的是 Socket s = new Socket("localhost", 6666);

最后要 catch(UnknownHostException e),UnknownHostException 小于 IOException 所以要放前面。


UDP 通信模型

示例:

// UDPServer 接收并打印来自客户端的数据
import java.net.*;
import java.io.*;

public class UDPServer {
    public static void main(String[] args) {
        try {
            byte[] buf = new byte[1024];
            DatagramPacket dp = new DatagramPacket(buf, buf.length);
            DatagramSocket ds = new DatagramSocket(8888);
            while(true) {
                ds.receive(dp);
                //ByteArrayInputStream bais = new ByteArrayInputStream(buf);
                //DataInputStream dis = new DataInputStream(bais);
                //System.out.println("UDPClient: " + dis.readUTF());
               System.out.println("UDPClient: " + new String(buf, 0, dp.getLength()));
            }           
        } catch (IOException e) {
            System.out.println("UDPServer Error!!!");
            e.printStackTrace();
        }
    }
}


// UDPClient 发送数据给服务器
import java.net.*;
import java.io.*;

public class UDPClient {
    public static void main(String[] args) {
        try {
            //ByteArrayOutputStream baos = new ByteArrayOutputStream();         
            //DataOutputStream dos = new DataOutputStream(baos);
            
            //dos.writeUTF("Hello HYJ!");
            //dos.flush();

            //byte[] buf = baos.toByteArray();
           byte[] buf = (new String("Hello HYJ!")).getBytes();
            System.out.println("buf.length = " + buf.length);
            
            DatagramPacket dp = new DatagramPacket(buf, buf.length, new InetSocketAddress("127.0.0.1", 8888));
            DatagramSocket ds = new DatagramSocket(7777);
            
            ds.send(dp);
            ds.close();
            
        } catch(IOException e) {
            e.printStackTrace();
        }
    }
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Android中高级开发

Android开发之漫漫长途 XIX——HTTP

该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列。该系列引用了《Android开发艺术探索...

13320
来自专栏Golang语言社区

Golang进阶——TCP网络编程详解

介绍 Golang是谷歌设计开发的语言,在Golang的设计之初就把高并发的性能作为Golang的主要特性之一,也是面向大规模后端服务程序。在服务器端网络通信是...

75970
来自专栏desperate633

设计模式之备忘录模式(Memento模式)引入备忘录模式备忘录模式的实例备忘录模式分析

我们在使用文本编辑器的时候,一般如果不小心误操作了,按ctrl+z就可以恢复之前的状态,撤销(undo)操作。 撤销的操作,实际上有两步,一是要保存之前的状态...

9620
来自专栏林冠宏的技术文章

基于 xorm 的服务端框架 XGoServer

作者:林冠宏 / 指尖下的幽灵 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 博客:htt...

28150
来自专栏安富莱嵌入式技术分享

【RL-TCPnet网络教程】第12章 TCP传输控制协议基础知识

本章节为大家讲解TCP(Transmission Control Protocol,传输控制协议),通过本章节的学习,需要大家对TCP有个基本的认识,方便后面章...

14230
来自专栏Golang语言社区

TCP、UDP、IP 协议分析

互连网早期的时候,主机间的互连使用的是NCP协议。这种协议本身有很多缺陷,如:不能互连不同的主机,不能互连不同的操作系统,没有纠错功能。为了改善这种缺点,大牛弄...

47730
来自专栏惨绿少年

网络基础二 tcp/ip协议簇 端口 三次握手 四次挥手 11种状态集

第1章 概念介绍 1.1 VLAN 1.1.1 什么是VLAN VLAN(Virtual LAN),翻译成中文是“虚拟局域网”。LAN可以是由少数几台家用计算...

23400
来自专栏开发与安全

linux网络编程之TCP/IP基础(三):IP数据报格式和IP地址路由

一、IP数据报格式 IP数据报格式如下: ? 注:需要注意的是网络数据包以大端字节序传输,当然头部也得是大端字节序,也就是说: The most signifi...

31870
来自专栏友弟技术工作室

iptsbles系列一

iptables系列之基础原理 ? linux:网络防火墙 netfilter:frame 框架 网络过滤器 iptables:数据报文过滤,NA...

33350
来自专栏信安之路

浅谈ddos的测试方式

DOS(denial of service--拒绝服务)攻击的目的是使服务正常功能不可用。不像其他类型的攻击的目的是获取敏感信息,Dos攻击是不会威胁到敏感信息...

29200

扫码关注云+社区

领取腾讯云代金券