Java|网络编程

1.网络编程概述

网络模型一般有两种:

  1. OSI(Open System Interconnection开放系统互连)七层参考模型
  2. TCP/IP四层参考模型
    在这里插入图片描述
    OSI(Open System Interconnection开放系统互连)七层参考模型

网络模型7层概述:
1.物理层
主要定义物理设备标准,如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。
它的主要作用是传输比特流(就是由1、0转化为电流强弱来进行传输,到达目的地后在转化为1、0)。这一层的数据叫做比特。
2. 数据链路层
主要将从物理层接收的数据进行MAC地址(网卡的地址)的封装与解封装。常把这一层的数据叫做帧。在这一层工作的设备是交换机,数据通过交换机来传输。
3. 网络层
主要将从下层接收到的数据进行IP地址(例192.168.0.1)的封装与解封装。在这一层工作的设备是路由器,常把这一层的数据叫做数据包。
4. 传输层
定义了一些传输数据的协议和端口号(WWW端口80等),如:TCP(传输控制协议,传输效率低,可靠性强,用于传输可靠性要求高,数据量大的数据),UDP(用户数据报协议,与TCP特性恰恰相反,用于传输可靠性要求不高,数据量小的数据,如QQ聊天数据就是通过这种方式传输的)。
主要是将从下层接收的数据进行分段和传输,到达目的地址后再进行重组。常常把这一层数据叫做段。
5. 会话层
通过传输层(端口号:传输端口与接收端口)建立数据传输的通路。主要在你的系统之间发起会话或者接受会话请求(设备之间需要互相认识可以是IP也可以是MAC或者是主机名)
6. 表示层
主要是进行对接收的数据进行解释、加密与解密、压缩与解压缩等(也就是把计算机能够识别的东西转换成人能够能识别的东西(如图片、声音等)。
7. 应用层
主要是一些终端的应用,比如说FTP(各种文件下载),WEB(IE浏览),QQ之类的(可以把它理解成我们在电脑屏幕上可以看到的东西.就是终端应用)。

2.网络编程三要素

  1. IP地址:InetAddress: 网络中设备的标识,不易记忆,可用主机名
  2. 端口号: 用于标识进程的逻辑地址,不同进程的标识
  3. 传输协议: 通讯的规则常见协议:TCP,UDP

3.网络编程三要素之IP

3.1 IP概述

IP地址就是给每个连接在Internet上的主机分配的一个32bit地址。

3.2 IP地址的组成

IP地址 = 网络地址+主机地址
A类IP地址:第一段号码为网络地址,剩下的三段号码为本地计算机的号码
B类IP地址:前二段号码为网络地址,剩下的二段号码为本地计算机的号码
C类IP地址:前三段号码为网络地址,剩下的一段号码为本地计算机的号码

3.3 IP地址分类

  1. A类 1.0.0.1—127.255.255.254
    (1)10.X.X.X是私有地址(私有地址就是在互联网上不使用,而被用在局域网络中的地址)
    (2)127.X.X.X是保留地址,用做循环测试用的。
  2. B类 128.0.0.1—191.255.255.254
    其中:172.16.0.0—172.31.255.255是私有地址。
  3. C类 192.0.0.1—223.255.255.254
    其中,192.168.x.X是私有地址
  4. D类 224.0.0.1—239.255.255.254
  5. E类 240.0.0.1—247.255.255.254
  6. 特殊地址:127.0.0.1 回环地址,可用于测试本机的网络是否有问题.

3.4 InetAddress类

InetAddress类的概述
为了方便我们对IP地址的获取和操作,java提供了一个类InetAddress 供我们使用。此类表示互联网协议 (IP) 地址。
此类没有构造方法,只有成员方法。
常用的方法:

  1. public static InetAddress getByName(String host)
    在给定主机名的情况下确定主机的 IP 地址,返回一个InetAddress 类的对象。
  2. static InetAddress getLocalHost()
    返回本地主机。
    方法1和方法2都可以获取一个InetAddress类的对象。
  3. public String getHostAddress()
    返回 IP 地址字符串(以文本表现形式)。
  4. public String getHostName()
    获取此 IP 地址的主机名
public class MyTest1 {
    public static void main(String[] args) throws UnknownHostException {
    	//获取一个InetAddress类的对象
        InetAddress inetAddress = InetAddress.getByName("192.168.43.146");
        System.out.println(inetAddress.getHostAddress());
        System.out.println(inetAddress.getHostName());
		System.out.println("**************");
		//获取一个InetAddress类的对象
        InetAddress localHost = InetAddress.getLocalHost();
        System.out.println(localHost.getHostName());
        System.out.println(localHost.getHostAddress());

    }
}

输出:

192.168.43.146
LS--20170210IRR
**************
LS--20170210IRR
192.168.43.146

4.网络编程三要素之端口

  1. 物理端口:网卡口
  2. 逻辑端口:我们一般指的端口指的就是逻辑端口
    a.每个网络程序都会有一个逻辑端口
    b.不同进程用不同的逻辑端口标识
    c.有效端口:0-65535(两个字节),其中0~1023系统使用或保留端口。

5.网络编程三要素之协议

常用的协议有TCP协议和UDP协议

  1. TCP
    a.建立连接,形成传输数据的通道
    b.在连接中进行大数据量传输
    c.需要连接所以是可靠协议
    d.必须建立连接,效率会稍低
  2. UDP
    a.将数据源和目的封装成数据包中,不需要建立连接
    b.每个数据报的大小在限制在64k
    c.因无连接,是不可靠协议
    d.不需要建立连接,速度快

6.Socket套接字

Socket=IP+端口号

Socket套接字概述:
网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。

Socket套接字概述:
网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。

7.使用UDP协议进行通信

在这里插入图片描述

7.1 UDP协议使用到的类

1.DatagramSocket类
此类表示用来发送和接收数据报包的套接字。在 DatagramSocket 上总是启用 UDP 广播发送。

构造方法:

  • DatagramSocket() 用于客户端
    构造数据报套接字并将其绑定到本地主机上任何可用的端口。
  • DatagramSocket(int port) 用于服务端
    创建数据报套接字并将其绑定到本地主机上的指定端口。

成员方法:

  • close()
    关闭此数据报套接字。
  • receive(DatagramPacket p)
    从此套接字接收数据报包。
  • send(DatagramPacket p)
    从此套接字发送数据报包。

2.DatagramPacket类
此类表示数据报包。
数据报包用来实现无连接包投递服务。每条报文仅根据该包中包含的信息从一台机器路由到另一台机器。从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。不对包投递做出保证。

构造方法:

  • DatagramPacket(byte[] buf, int length)
    构造 DatagramPacket,用来 接收 长度为 length 的数据包。

  • DatagramPacket(byte[] buf, int length, InetAddress address, int port)
    构造数据报包,用来将长度为 length 的包 发送 到指定主机上的指定端口号。

成员方法:

  • byte[] getData()
    返回数据缓冲区。
  • int getLength()
    返回将要发送或接收到的数据的长度。

7.2 几个案例

7.2.1 简单的UDP协议发送与接收数据

public class Client {
    public static void main(String[] args) throws IOException {

        DatagramSocket datagramSocket = new DatagramSocket();

        byte[] bytes ="我是客户端".getBytes();
        InetAddress inetAddress = InetAddress.getByName("192.168.43.146");
        DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, inetAddress, 6666);
        datagramSocket.send(datagramPacket);

        datagramSocket.close();
    }
}

public class Service {
    public static void main(String[] args) throws IOException {
        DatagramSocket datagramSocket = new DatagramSocket(6666);

        byte[] bytes = new byte[1024];
        DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
        System.out.println("服务器已开启...");

        datagramSocket.receive(datagramPacket);
        byte[] data = datagramPacket.getData();
        int length = datagramPacket.getLength();
        String hostName = datagramPacket.getAddress().getHostName();
        String s = new String(data,0,length);
        System.out.println(hostName+"发来如下消息:"+s);
    }
}

7.2.2 UDP协议发送端的数据来自于键盘录入

public class Client {
    public static void main(String[] args) throws IOException {

        DatagramSocket datagramSocket = new DatagramSocket();

        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        while (true){
            System.out.println("输入你要发送的数据:");
            String s1 = reader.readLine();
            if(s1.equals("886")){
                break;
            }
            byte[] bytes = s1.getBytes();
            DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.43.146"), 8888);
            datagramSocket.send(datagramPacket);
        }

        datagramSocket.close();
    }
}

public class Service {
    public static void main(String[] args) throws IOException {
        DatagramSocket datagramSocket = new DatagramSocket(8888);

        System.out.println("服务器已开启...");
        while (true){
            byte[] bytes = new byte[1024];

            DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
            datagramSocket.receive(datagramPacket);

            byte[] data = datagramPacket.getData();
            int length = datagramPacket.getLength();
            InetAddress address = datagramPacket.getAddress();
            String hostName = address.getHostName();
            String hostAddress = address.getHostAddress();

            System.out.println(hostAddress + "---" + hostName + "给您发来如下消息:"+new String(data,0,length));
        }
    }
}

将上述代码改写成多线程的形式

public class MyTest {
    public static void main(String[] args) {
        //多线程改写demo2
        Client client = new Client();
        Service service = new Service();
        client.start();
        service.start();
    }
}

public class Client extends Thread{
    @Override
    public void run() {
        try {
            DatagramSocket datagramSocket = new DatagramSocket();

            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            while (true){
                System.out.println("输入你要发送的数据:");
                String s1 = reader.readLine();
                if(s1.equals("886")){
                    break;
                }
                byte[] bytes = s1.getBytes();
                DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.43.146"), 8888);
                datagramSocket.send(datagramPacket);
            }

            datagramSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

public class Service extends Thread{

    @Override
    public void run() {
        try {
            DatagramSocket datagramSocket = new DatagramSocket(8888);

            System.out.println("服务器已开启...");
            while (true){
                byte[] bytes = new byte[1024];

                DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
                datagramSocket.receive(datagramPacket);

                byte[] data = datagramPacket.getData();
                int length = datagramPacket.getLength();
                InetAddress address = datagramPacket.getAddress();
                String hostName = address.getHostName();
                String hostAddress = address.getHostAddress();

                System.out.println(hostAddress + "---" + hostName + "给您发来如下消息:"+new String(data,0,length));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

7.2.3 基于UDP协议的多线程实现聊天室程序

要求:有2个用户A和B,用户A的主线程作为服务器,接收来自B的消息;子线程作为客户端,向B发送信息;B亦然。
A:192.168.43.146 服务器暴露的端口:7777
B:192.168.43.146 服务器暴露的端口:8888

public class A {
    //多线程实现聊天室程序
    //A:192.168.43.146  服务器暴露的端口:7777
    //B:192.168.43.146  服务器暴露的端口:8888
    public static void main(String[] args) throws IOException {
        new Thread(){
            @Override
            public void run() {
                try {
                    DatagramSocket datagramSocket = new DatagramSocket();

                    BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
                    while (true){
                        System.out.println("输入你要发送给B的数据:");
                        String s1 = reader.readLine();
                        if(s1.equals("886")){
                            break;
                        }
                        byte[] bytes = s1.getBytes();
                        DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.43.146"), 8888);
                        datagramSocket.send(datagramPacket);
                    }

                    datagramSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }.start();

        receiveFun();
    }

    private static void receiveFun() throws IOException {

        DatagramSocket datagramSocket = new DatagramSocket(7777);

        System.out.println("A服务器已开启...");
        while (true){
            byte[] bytes = new byte[1024];

            DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
            datagramSocket.receive(datagramPacket);

            byte[] data = datagramPacket.getData();
            int length = datagramPacket.getLength();
            InetAddress address = datagramPacket.getAddress();

            System.out.println( "B给您发来如下消息:"+new String(data,0,length));
        }
    }
}


public class B {
        public static void main(String[] args) throws IOException {
            new Thread(){
                @Override
                public void run() {
                    try {
                        DatagramSocket datagramSocket = new DatagramSocket();

                        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
                        while (true){
                            System.out.println("输入你要发送给A的数据:");
                            String s1 = reader.readLine();
                            if(s1.equals("886")){
                                break;
                            }
                            byte[] bytes = s1.getBytes();
                            DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.43.146"), 7777);
                            datagramSocket.send(datagramPacket);
                        }

                        datagramSocket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }.start();
            
            receiveFun();
        }

        private static void receiveFun() throws IOException {

            DatagramSocket datagramSocket = new DatagramSocket(8888);

            System.out.println("B服务器已开启...");
            while (true){
                byte[] bytes = new byte[1024];

                DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
                datagramSocket.receive(datagramPacket);

                byte[] data = datagramPacket.getData();
                int length = datagramPacket.getLength();
                InetAddress address = datagramPacket.getAddress();

                System.out.println( "A给您发来如下消息:"+new String(data,0,length));
            }
        }
    }


8.使用TCP协议进行通信

在这里插入图片描述

8.1 TCP协议使用到的类

1.Scoket类
此类实现 客户端套接字(也可以就叫“套接字”)。套接字是两台机器间通信的端点。

构造方法

  • Socket(InetAddress address, int port)
    参数1:服务器的IP地址; 参数2:服务器的端口

    创建一个流套接字并将其连接到指定 IP 地址的指定端口号。

成员方法

  • close()
    关闭此套接字。

  • InputStream getInputStream()
    返回此套接字的输入流。

  • OutputStream getOutputStream()
    返回此套接字的输出流。

  • void shutdownInput()
    此套接字的输入流置于“流的末尾”。

  • void shutdownOutput()
    禁用此套接字的输出流。

2.ServerSocket类
此类实现服务器套接字。服务器套接字等待请求通过网络传入。它基于该请求执行某些操作,然后可能向请求者返回结果。
构造方法

  • ServerSocket(int port)
    创建绑定到特定端口的服务器套接字。

成员方法

  • Socket accept() 阻塞式方法 此方法只能使用一次!!!
    侦听并接受到此套接字的连接。
  • close()
    关闭此套接字。

8.2 几个案例

8.2.1 简单的TCP协议发送与接收数据

public class Client {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("192.168.43.146", 5555);

        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("你好".getBytes());

        socket.close();
    }
}

public class Service {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(5555);
        System.out.println("服务器已开启...");
        Socket socket = serverSocket.accept();

        InputStream inputStream = socket.getInputStream();
        byte[] bytes = new byte[1024];
        int len = inputStream.read(bytes);
        String s = new String(bytes, 0, len);
        System.out.println(s);

        serverSocket.close();
    }
}

8.2.2 服务器给客户端一个反馈

客户端发送数据,服务器接受数据并给出反馈

public class Client {
    public static void main(String[] args) throws IOException, InterruptedException {
        Socket socket = new Socket("192.168.43.146", 5656);

        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("hi!".getBytes());

        InputStream inputStream = socket.getInputStream();
        byte[] bytes = new byte[1024];
        int read = inputStream.read(bytes);
        System.out.println(new String(bytes,0,read));

        socket.close();
    }
}

public class Service {
    public static void main(String[] args) throws IOException, InterruptedException {
        ServerSocket serverSocket = new ServerSocket(5656);
        
        System.out.println("服务器已经开启....");
        Socket accept = serverSocket.accept();
        InputStream inputStream = accept.getInputStream();
        byte[] bytes = new byte[1024];
        int read = inputStream.read(bytes);
        String s = new String(bytes, 0, read);
        System.out.println(s);

        OutputStream outputStream = accept.getOutputStream();
        outputStream.write("服务器已经接收到客户端的数据".getBytes());

        serverSocket.close();
    }
}

8.2.3 客户端键盘录入服务器写到文本文件

public class Client {
    public static void main(String[] args) throws IOException, InterruptedException {
        //客户端键盘录入服务器写到文本文件
        Socket socket = new Socket("192.168.43.146", 5656);

        while (true){
            OutputStream outputStream = socket.getOutputStream();

            Scanner scanner = new Scanner(System.in);
            System.out.println("请输入:");
            String s = scanner.nextLine();
            outputStream.write(s.getBytes());
            if(s.equals("886")){
                break;
            }
        }
        socket.close();
    }
}

public class Service {
    public static void main(String[] args) throws IOException, InterruptedException {
        ServerSocket serverSocket = new ServerSocket(5656);

        System.out.println("服务器已经开启....");
        Socket accept = serverSocket.accept();
        FileOutputStream fileOutputStream = new FileOutputStream("aaa.txt");
        while (true){
            InputStream inputStream = accept.getInputStream();
            byte[] bytes = new byte[1024];
            int read = inputStream.read(bytes);

            fileOutputStream.write(bytes,0,read);
            fileOutputStream.write("\n".getBytes());
            fileOutputStream.flush();
        }

    }
}

8.2.4 客户端读取文本文件服务器控制台输出

public class Client {
    public static void main(String[] args) throws IOException {
        //客户端读取文本文件服务器控制台输出
        Socket socket = new Socket("192.168.43.146", 5656);
        OutputStream outputStream = socket.getOutputStream();
        //包装
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
        BufferedReader reader = new BufferedReader(new FileReader("aaa.txt"));

        String line=null;
        while ((line=reader.readLine())!=null){
            writer.write(line);
            writer.newLine();
            writer.flush();
        }
        //手动写一个结束标记
        writer.write("over");
        writer.newLine();
        writer.flush();

        socket.close();
    }
}


public class Service {
    public static void main(String[] args) throws IOException {
        //客户端读取文本文件服务器控制台输出
        ServerSocket serverSocket = new ServerSocket(5656);

        System.out.println("服务器已经开启....");
        Socket accept = serverSocket.accept();

        InputStream inputStream = accept.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        String s1 = new String();
        s1=null;
        while (true){
            s1=reader.readLine();
            if(s1.equals("over")){
                break;
            }
            System.out.println(s1);
        }
        serverSocket.close();
    }
}

8.2.5 TCP上传文本文件并给出反馈

TCP传输容易出现的问题:
客户端连接上服务端,两端都在等待,没有任何数据传输。

原因分析:
因为read方法或者readLine方法是阻塞式。

解决办法:

  • 1.自定义结束标记
  • 2.使用shutdownInput,shutdownOutput方法。

方式2的代码:

public class Client {
    public static void main(String[] args) throws IOException {
        //TCP协议上传文本文件并给出反馈
        Socket socket = new Socket("192.168.43.146", 5656);
        OutputStream outputStream = socket.getOutputStream();
        //包装
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
        BufferedReader reader = new BufferedReader(new FileReader("aaa.txt"));

        String line=null;
        while ((line=reader.readLine())!=null){
            writer.write(line);
            writer.newLine();
            writer.flush();
        }


        socket.shutdownOutput();//禁用此套接字的输出流

        InputStream inputStream = socket.getInputStream();
        byte[] bytes = new byte[1024];
        int read = inputStream.read(bytes);
        System.out.println(new String(bytes, 0, read));

        socket.close();
        writer.close();
        reader.close();
    }
}

public class Service {
    public static void main(String[] args) throws IOException, InterruptedException {
        //TCP协议上传文本文件并给出反馈
        ServerSocket serverSocket = new ServerSocket(5656);

        System.out.println("服务器已经开启....");
        Socket accept = serverSocket.accept();
        InputStream inputStream = accept.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        BufferedWriter writer = new BufferedWriter(new FileWriter("aaa(2).txt"));

        String line=null;
        while ((line=reader.readLine())!=null){
            writer.write(line);
            writer.newLine();
            writer.flush();
        }

        OutputStream outputStream = accept.getOutputStream();
        outputStream.write("文件上传完毕".getBytes());

        serverSocket.close();
        writer.close();
        reader.close();

    }
}

8.2.6 多线程改进上传文本文件(空)

一个服务器,开启客户端的多个线程,同时向服务器上传数据。

在这里插入代码片

9 常用DOS 命令

DOS 命令意义
ipconfig -all获取本地IP,主机名,MAC地址
ing -a x.x.x.x获取x.x.x.x的主机名
net view获取局域网中的所有主机名
arp -a获取本局域网中的所有IP地址和物理地址
nbtstat -a 主机名获取MAC地址

https://blog.csdn.net/havedream_one/article/details/47071393 参考这篇文档可以提取局域网中其他主机的IP地址

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值