《Java核心技术 卷II》笔记——(9)Java网络编程

网络编程不等于网站编程,网络编程即使用套接字来达到进程间通信,现在一般称为TCP/IP编程;

网络?地址?数据包?

计算机网络把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大,功能强的网络系统,从而使众多的计算机可以方便的互相传递信息,共享硬件,软件,数据信息等资源;

网络是相互发送和接受数据的计算机和其他设备的集合,每一个设备就是一个网络节点(node),每一个计算机是一个主机(host);

每个网络节点有地址,以太网分配物理地址,Internet服务器分配Internet地址,地址可以有标识名字,但是不与地址锁定;

数据交换使用包交换,包有发送人和目标地址信息,可以互不干扰的共用线缆,可以进行安全校验,需要提供协议定义数据传递规则;

网络通信协议/接口?

网络通信协议:计算机网络中实现通信必须有一些约定,即通信协议;包括对速率传输代码代码结构传输控制步骤出错控制等制定的标准;

为了使两个节点之间能进行对话,必须在他们之间建立通信工具(即接口),使彼此之间,能进行信息交换。接口包括两部分:

  • 硬件装置:实现结点之间的信息传送
  • 软件装置:规定双方进行通信的约定协议

网络分层?为什么分层?

为什么要分层:由于结点之间联系很复杂,在制定协议时,把复杂成份分解成一些简单的成份,再将它们复合起来。最常用的复合方式就是层次方式,及同层间可以通信,上一层可以调用下一层,而与再下一层不发生关系。各层互不影响,利于系统的开发和扩展。

通信协议的分层规定:把用户应用程序作为最高层,把物理通信线路作为最底层,将其间的协议处理分为若干层,规定每层处理的任务,也规定每层的接口标准。

网络协议栈?(图)

image.png

TCP/IP4层模型?(图)

image.png

Java网络类只工作在应用层传输层上;

  • 主机网络层:连接硬件;

  • 网际层:用于路由和寻址,支持不同类型的主机网络层相互对话,包含IPv4和IPv6两个协议,以下是IPv4数据报结构;

  • 传输层:负责确保包以发送的顺序接受,保证数据没有丢失或破坏,包含对丢失或破坏的数据进行有序重发的TCP(传输控制协议)协议和检测破坏包、但不保证有序的UDP(数据报协议)协议;

  • 应用层:向用户传输数据的层,用于Web的HTTP、用于电子邮件的SMTP、POP和IMAP、用于文件传输的FTP、FASP和TFTP、用于文件访问的NFS、用于文件共享的Gnutella和BitTorrent、用于语音通信的回话启动协议SIP和Skype;

*IP/TCP/UDP?

IP: 允许任意两点之间有多个路由,TCP确认连接两端收到IP包,Java在传输层只支持TCP和UDP;

IP地址?

IPv4地址,4字节地址,例如192.168.6.190;
包的首部保护目的地址和源地址;
IPv4地址已经用完,目前在向IPv6地址过渡;
IPv6地址,16字节地址,例如FEDC:7654:3210:FEDC:BA98:7654:3210;

域名(DNS)?

域名(DNS)用于记忆主机名,并在使用时转换为ip地址;
IP地址会随着时间变换;
127.0.0.1表示本地回送地址;
IPv6的本地回送地址为::1;

端口?

  • IP地址用来标识一台计算机,但是一台计算机上可能提供多种网络应用程序,如何来区分这些不同的程序呢?这就要用到端口;

  • 端口是虚拟的概念,并不是说在主机上真的有若干个端口;

  • 通过端口,可以在一个主机上运行多个网络应用程序;端口的表示是一个16位的二进制整数,2个字节,对应十进制的0~65535;

  • MySQL(3306),Oracle(1521),Tomcat(8080)等等程序都有自己的端口;

怎么查看端口?

用命令提示符cmd查看所有端口:netstat -ano ;
查看具体程序:使用任务管理器查看PID;

TCP/IP协议?

  • IP协议是一个分组交换协议,不保证可靠传输,一个数据包通过IP协议传输会自动分成若干小的数据包然后通过网络进行传输;

  • TCP(Transmission Control Protocol) 协议是一个传输控制协议,建立再IP协议之上,IP协议负责传输数据包,TCP协议负责控制传输数据包;

  • TCP协议面向连接,传输之前需要先建立连接,然后才能传输数据,传输完成后断开连接;

  • TCP协议是一个可靠传输协议,他通过接收确认,超时重传实现;

  • TCP协议支持双向通信(双工),双方可以同时传输和接收数据;

UDP协议?

UDP(User Datagram Protocol)协议是数据报文协议,不面向连接,不保证可靠传输,由于UDP协议传输效率高,通常用来传输视频等能容忍丢失部分数据的文件;

客户/服务器模型?

服务端发送数据,客户端接收数据;
对等端通过服务器程序实现相互通信;

Socket?

  • Socket通常称为套接字,用于应用程序之间建立远程连接,Socket内部通过TCP/IP协议进行数据传输,可以简单的理解为对IP地址和端口号的描述;

  • Socket接口是由计算机操作系统提供的,编程语言提供对Socket接口调用的封装;

  • 通常计算机同时运行多个应用程序,仅仅有IP地址是无法确定由哪个应用程序接收数据,所以操作系统抽象出Socket接口,每个应用程序对应不同的socket(每个网络应用程序分配不同的端口号);

  • 端口号的范围是0~65535,小于1024的端口需要管理员权限,大于1024的端口可以任意用户的应用程序打开;

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

  • Socket是两台注解直接的一个连接,可以完成7个基本操作:连接远程机器、发送数据、接受数据、关闭连接、绑定端口、监听入站数据、在绑定端口上接受来自远程机器的连接;

网络地址和端口相关的类?

InetAddress类?
说到IP地址,就要引入一个类:InetAddress;表示互联网协议 (IP) 地址;

eg:

 @Test
 public void func_01() {//测试Socket类、InetAddress类
  Socket s = null;
  Scanner sin = null;
  try {
    s = new Socket("time-a.nist.gov", 13); // Socket套接字绑定要访问的(主机,端口)
    InetAddress[] address = InetAddress.getAllByName("time-a.nist.gov"); // 主机名对应一(多)个IP地址
    for(InetAddress a:address){
      System.out.println(a);
    }
  // s.setSoTimeout(2000);//设置超时时间
  InputStream in = s.getInputStream();//从套接字获取
  OutputStream out = s.getOutputStream();//
  sin = new Scanner(in, "UTF-8");
  System.out.println(s.isConnected());//是否连接
  } catch (IOException e) {
    e.printStackTrace();
  }
  while (sin.hasNextLine()) {
    String line = sin.nextLine();
    System.out.println(line);
  }
  System.out.println(s.isClosed());//是否关闭
}

InetSocketAddress类?
说到端口,则要引入一个类:InetSocketAddress;实现 IP 套接字地址(IP 地址 + 端口号);

eg:

@Test
public void func_02() {//测试
  InetSocketAddress inetSocketAddress = new 
  InetSocketAddress("127.0.0.1",8082);
  System.out.println(inetSocketAddress.getHostName());
 // 获得InetSocketAddress的端口
  System.out.println(inetSocketAddress.getPort());
  System.out.println(inetSocketAddress.getHostString());
 //返回一个InetAddress对象(IP对象)
  InetAddress address = inetSocketAddress.getAddress();
}

URL?

  • URI=URL+URN

  • URI:Uniform Resource Identifier ,统一资源标志符。

  • URL:Uniform Resource Locator,统一资源定位符。

  • URN:Uniform Resource Name,统一资源命名。

网络三大基石HTMLHTTPURL

在www上,每一信息资源都有统一且唯一的地址,即统一资源定位符。Uniform Resource Locator。

如:https://localhost:8080/index.html ,有4部分组成。(协议,主机域名或IP,端口号,资源文件名)

eg:

@Test
public void func_02_1() throws MalformedURLException {//测试
 URL url2 = new URL("https://www.bilibili.com/");
 //获取此的授权部分 URL 。
 System.out.println(url2.getAuthority());
 //获取此 URL的文件名。
 System.out.println(url2.getFile());
 //获取端口
 System.out.println(url2.getPort());
 //获取主机
 System.out.println(url2.getHost());
 //获得默认端口
 System.out.println(url2.getDefaultPort());
 //获得路径
 System.out.println(url2.getPath());
 //获取该 URL的userInfo部分。
 System.out.println(url2.getUserInfo());
}

Socket类怎么使用?

UDP编程?

  • 使用基于UDP协议的Socket网络编程实现;
  • 不需要利用IO流实现数据的传输;
  • 每个数据发送单元被统一封装成数据包的方式,发送方将数据包发送到网络中,数据包在网络中去寻找他的目的地,一切以包为中心;

UDP基本概念:

DatagramSocket:用于发送或接收数据包的套接字;
DatagramPacket:数据包;

eg:

1. 接收方;

//1.开放一个端口
DatagramSocket socket = new DatagramSocket(5051);
//2.准备容器接收
byte[] receiveBuf = new byte[100];
//3.等待包裹容器封包
DatagramPacket packet = new DatagramPacket(receiveBuf, receiveBuf.length);
System.out.println("等你包裹来。。。。");
while (true) {
    //4.接收包裹
 socket.receive(packet);
 //5.解析包裹
 String receStr = new String(packet.getData(), 0, packet.getLength());
 System.out.println("我收到了:" + receStr);
 if (receStr.equals("exit")) {
        break;
 }
}
//6.释放资源
socket.close();
2. 发送方;

//1.指定一个端口进行发送
DatagramSocket socket = new DatagramSocket();
//2.指定一个IP
InetAddress addr = InetAddress.getByName("127.0.0.1");
int port = 5051;
//3.准备一个小容器
byte[] sendBuf;
while (true){
 Scanner scanner = new Scanner(System.in);
 System.out.println("你要发什么东西:");
 String s = scanner.nextLine();
 //4.加入要放的数据
 sendBuf = s.getBytes();
 //5.数据打包
 DatagramPacket packet = new DatagramPacket(sendBuf,sendBuf.length,addr,port);
 //6.发送包
 socket.send(packet);
 if (s.equals("exit")){
  break;
 }
}
//7.释放资源
socket.close();

TCP编程?

  • 使用基于TCP协议的Socket网络编程实现;
  • TCP协议基于请求响应模式;
  • 在网络通讯中,第一次主动发起通讯的程序被作为客户端程序;
  • 第一次通讯中等待连接的程序被称作服务器程序;
  • 利用IO流实现数据的传输;

eg:

服务端的一个ServerSocket可以同时和多个客户端建立连接进行双向通信,实现起来也很简单,在设置好监听端口后,在一个无限for循环中调用ServerSocket的accept()方法,返回与客户端新建的连接,再启动线程或者使用线程池来处理客户端的请求,这样就可以同时处理多个客户端的连接;

class TCPServer { // 服务器类,绑定本机IP-端口;accept()轮询连接者;使用线程池管理handler去处理连接后的业务;
  @SuppressWarnings("resource")
  public static void main(String[] args) throws Exception {
  ServerSocket ss = new ServerSocket(6666);
  System.out.println("TCP server ready.");
  for (;;) {  // 无限for循环中返回客户端新建的连接
  Socket sock = ss.accept();
  // 设置线程要处理的任务
  Runnable handler = new TimeHandler(sock);
  // 使用Java提供的ExecutorService创建线程池
  ExecutorService executor = Executors.newCachedThreadPool();
  // 线程处理任务
  executor.submit(handler);
  // 任务处理完毕,关闭线程
  executor.shutdown();
  }
 }
}
class TimeHandler implements Runnable { //连接后的业务类,继承Runnable;
    Socket sock;
    TimeHandler(Socket sock) {
        this.sock = sock;
    }
    @Override
    public void run() {
        try(BufferedReader reader = new BufferedReader(new InputStreamReader(sock.getInputStream(), StandardCharsets.UTF_8))) {
            try(BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream(), StandardCharsets.UTF_8))) {
                for(;;) {
                    String cmd = reader.readLine();
                    if("q".equals(cmd)) {
                        writer.write("bye!\n");
                        writer.flush();
                        break;
                    }
                    else if("time".equals(cmd)) {
                        writer.write(LocalDateTime.now().toString() + "\n");
                        writer.flush();
                    }
                    else {
                        writer.write("require data\n");
                        writer.flush();
                    }
                }
            }
        }
        catch(IOException e) {
            e.printStackTrace();
        }
        finally {
            try {
              this.sock.close();
            } catch(IOException e) {
              e.printStackTrace();
            }
        }
    }
}
class TestClient {//客户端类;
 public static void main(String[] args) throws IOException {
 //创建同一连接
 Socket s = new Socket("127.0.0.1",6666);
 DataOutputStream dos = new DataOutputStream(s.getOutputStream());
 dos.writeUTF("hello,world!");
 }
}

小结

  1. 一般的网络编程都称为Socket编程,Socket的英文意思是“插座”(图)

     

    image.png

     

    2.两台电脑都安装上一个插座,然后使用一根线的两端插到两台电脑的插座上,这样两台电脑就建立好了连接,这个插座就是Socket;

  2. 因为互相之间都能互相通信,因此Server只是从逻辑意义上来讲,但从技术意义上来讲,只有TCP才会分Server和Client;对于UDP来说,从严格意义上来讲,并没有所谓的Server和Client;TCP的Server的插座就叫ServerSocket,Client的插座就叫Socket;

  3. 两台计算机互相连接,那么首先必须得知道它们的IP地址,但是只提供IP地址是不够的,还必须要有连接的端口号,也就是要连接到哪个应用程序上。

  4. 端口号是用来区分一台机器上不同的应用程序的。端口号在计算机内部是占2个字节。一台机器上最多有65536个端口号。一个应用程序可以占用多个端口号。端口号如果被一个应用程序占用了,那么其他的应用程序就无法再使用这个端口号了。记住一点,编写的程序要占用端口号的话占用1024以上的端口号,1024以下的端口号不要去占用,因为系统有可能会随时征用;端口号本身又分为TCP端口和UDP端口,TCP的8888端口和UDP的8888端口是完全不同的两个端口;TCP端口和UDP端口都有65536个;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值