记录我的java之路——day16(周更)

day3-网络编程(上)

  • 网络概述

  • 网络协议(TCP/IP、UDP)

  • IP与端口

  • C/S、B/S

  • InetAddress类

  • Socket编程

网络概述

概述

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

计算机网络优点

  • 资源共享

  • 分布式计算

网络分类

  • 局域网(LAN,Local Area Network)

  • 都市网(MAN,Metropolis Area Network)

  • 广域网(WAN,Wide Area Network)

网络协议

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

  • TCP/IP

  • UDP

IP与端口

IP

IP协议(Internet Protocol)是网络上的计算机进行连接的基础,每一台主机在不同网络中都有一个唯一的ip地址,通过该地址主机之间可以完成网路联通实现信息交互;IP地址通常由四个字节(IPV4)构成,由于互联网发展迅速,目前IPV4地址(40多亿)已经接近枯竭,因此出现了更为庞大的ipV6。

端口(Port)

端口号是应用程序在主机中的唯一标识,是当前应用与外部应用通信的通道,其中包含一些数据结构和IO缓冲区,端口的取值范围为0~65535之间;通常端口分为三类

公认端口(Well Known Ports):从0到1023,它们紧密绑定(Binding)一些服务

注册端口(Registered Ports):从1024到49151。它们松散地绑定一些服务

动态和/或私有端口(Dynamic and/or Private Ports):从49152到65535。理论上不应为服务分配这些端口

C/S、B/S

  • C/S:Client/Server客户端服务器模式

  • B/S:Browser/Server浏览器服务模式

InetAddress类

java中提供了java.net.InetAddress类用于对指定主机的进行操作,该类包含主机信息和ip地址等信息,InetAddress未提供公开的构造器,因此无法直接通过new构建对象,具体使用如下:

public class IpDemo {
​
    public static void main(String[] args) throws UnknownHostException {
        //根据主机名称获取ip对象(包含主机名和ip地址信息)
        InetAddress ip = InetAddress.getByName("DESKTOP-F8QEE0A");
        //获取主机名
        System.out.println(ip.getHostName());
        //获取主机地址
        System.out.println(ip.getHostAddress());
        
        byte[] b = ip.getAddress();
        for (byte c : b) {
            System.out.println(c);
        }
        
        //获取指定主机中的所有ip(包括ipv6)
        InetAddress[] ips = InetAddress.getAllByName("DESKTOP-F8QEE0A");
        for (InetAddress addr : ips) {
            System.out.println("--->"+addr);
        }
        
        b = new byte[]{(byte)192,(byte)168,(byte)4,(byte)254};
        //根据提供的原始ip的字节数组获取ip对象
        ip = InetAddress.getByAddress(b);
        System.out.println(ip);
        
        //本地主机获取
        System.out.println("获取本地主机地址:"+InetAddress.getLocalHost());
        System.out.println(InetAddress.getByName("localhost"));
        System.out.println(InetAddress.getByName("127.0.0.1"));
        //根据域名获取当前域名绑定的ip地址
        System.out.println(InetAddress.getByName("task.softeem.top"));
        System.out.println(InetAddress.getByName("www.baidu.com"));
    }
}

Socket通信

Socket通信包含TCP/IP和UDP协议的通信机制,其中TCP/IP协议为安全可靠协议,需要保证服务器和客户端正常建立连接之后方可通信,java中为TCP/IP协议提供的Socket通信工具主要由java.net.ServerSocket和java.net.Socket完成,常用构造器如下:

  • ServerSocket(int port):提供服务端套接字

  • Socket(String ip,int port):提供客户端套接字

通信原理:

以下为一个基于点对点的通信过程:

Server端:

public static void main(String[] args) throws IOException {
    //占据指定端口创建服务
    ServerSocket ss = new ServerSocket(6789);
    //开始监听,一旦有客户端连接,则获取跟此客户端通信的Socket对象
    Socket s = ss.accept();
    //获取基于Socket的输出流并包装为打印流(自动刷新)
    PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
    BufferedReader br = null;
    pw.println("已连接Softeem聊天室,准备跟服务器畅聊吧!!!");
    while(true){
        // 读取从Client端发送过来的消息
        br = new BufferedReader(new InputStreamReader(s.getInputStream()));
        String msg = br.readLine();
        System.out.println(s.getInetAddress().getHostAddress()+":"+msg);
        //读取控制台消息发送到Client端
        br = new BufferedReader(new InputStreamReader(System.in));
        msg = br.readLine();
        pw.println(msg);
    }
}

Client端:

public static void main(String[] args) throws UnknownHostException, IOException {
    //连接到指定地址指定端口的服务
    Socket s = new Socket("192.168.4.254",6789);
    BufferedReader br = null;
    //获取基于Socket的输出流并包装为打印流
    PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
    while(true){
        //读取来自Server端的消息
        br = new BufferedReader(new InputStreamReader(s.getInputStream()));
        String msg = br.readLine();
        System.out.println(s.getInetAddress().getHostAddress()+":"+msg);
        //读取控制台输入并发送到Server端
        br = new BufferedReader(new InputStreamReader(System.in));
        msg = br.readLine();
        pw.println(msg);
    }
}

从服务端传输文件到客户端(一对一)

FTPServer.java:

package com.softeem.net.socket;
​
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
​
public class FTPServer {
​
    public void start(File target) throws IOException{
        //创建一个服务器
        ServerSocket ss = new ServerSocket(5678);
        //开始监听
        Socket  s = ss.accept();
        //获取基于socket的输出流
        PrintStream ps = new PrintStream(s.getOutputStream());
        //获取目标文件的输入流
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(target));
        System.out.println("开始传输...");
        byte[] b = new byte[1024];
        int len = 0;
        while((len = bis.read(b)) != -1){
            ps.write(b, 0, len);
        }
        System.out.println("传输完成!");
        bis.close();
        ps.close();
        ss.close();
    }
    
    public static void main(String[] args) throws IOException {
    
        File target = new File("D:\\素材\\视频\\video.mp4");
        new FTPServer().start(target);
    }
​
}
​

FTPClient.java

package com.softeem.net.socket;
​
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
​
public class FTPClient {
​
    public static void main(String[] args) throws UnknownHostException, IOException {
        
        File f = new File("C:\\Users\\mrchai\\Desktop\\video.mp4");
        
        Socket s = new Socket("192.168.4.254",5678);
        //获取目标文件的输出流
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(f));
        //获取socket的输入流
        BufferedInputStream bis = new BufferedInputStream(s.getInputStream());
        byte[] b = new byte[1024];
        int len = 0;
        while((len = bis.read(b)) != -1){
            bos.write(b, 0, len);
        }
        bis.close();
        bos.close();
        s.close();
    }
}

原理图:

基于UDP协议的Socket通信

UDP(User Datagram Protocol)用户数据报协议,是一个不可靠的网络传输协议,原理为:将需要发送的数据打成数据报包(DatagramPacket)然后通过网络通道(DatagramSocket)发送,发送过程不能保证数据能及时送达,也不能保证数据报包的接收顺序跟发送顺序一致,但是传输效率相比TCP/IP协议较高。

UDP编程实例:

Sender.java

String msg = "听说女寝被盗?究竟是人性的扭曲,还是道德沦丧!!!";
byte[] b = msg.getBytes();
//将数据打包成数据报包
DatagramPacket dp = new DatagramPacket(
    b, 
    0, 
    b.length, 
    InetAddress.getByName("192.168.4.254"), 
    7788);
//创建网络通道
DatagramSocket ds = new DatagramSocket();
//发送
ds.send(dp);

Receiver.java

DatagramSocket ds = new DatagramSocket(7788);
//声明字节缓冲区
byte[] b = new byte[1024];
DatagramPacket dp = new DatagramPacket(b, 0, b.length);
//将消息接收到数据报包中
ds.receive(dp);
//解析数组中的数据为字符串消息
String s = new String(b,0,dp.getLength());
System.out.println(s);

与飞秋通信

由于飞秋内部协议基于IPMSG协议(飞鸽传书),底层也是UDP,所以通过该协议构建指定格式的消息也可以完成自定义程序实现跟飞秋通信,飞秋消息发送的协议模式为 (版本号:包编号:用户名:主机名:命令字:消息内容),例如"1​:100 :​ tom : toms:32:Hello,tom!​",另外飞秋的默认端口是2425。

public static void main(String[] args) throws IOException {
    String msg = "听说女寝被盗?究竟是人性的扭曲,还是道德沦丧!!!";
    msg = "1:100:mrchai:血饮狂刀:32:"+msg;
    byte[] b = msg.getBytes();
    //将数据打包成数据报包
    DatagramPacket dp = new DatagramPacket(
        b, 
        0, 
        b.length, 
        InetAddress.getByName("192.168.4.255"), 
        2425);
​
    //创建网络通道
    DatagramSocket ds = new DatagramSocket();
    //发送
    ds.send(dp);
}

练习:

  1. 完成一个点对点的聊天工具,要求客户端能够实现聊天记录的保存,根据日期,每天生成一个,比如:20180727.log ,格式如下(推荐UDP)

    【2018-07-27 15:32:33】小明 :今天天气真好啊!

    【2018-07-27 15:33:33】我:你为何如此优秀??

  2. 完成一个文件服务器,服务端对外公开一个目录,目录中包含N个标准文件,要求客户端能够任意下载目录中的指定文件(提示:Map集合,对象序列化)

猜你喜欢

转载自blog.csdn.net/qq_34304871/article/details/81274780