网络编程—IP、协议、端口

什么是网络编程

在网络通信协议下,不同计算机上运行的程序,进行的数据传输

  • 应用场景:即时通信、网游对战、金融证券、国际贸易、邮件等等。

    不管是什么场景,都是计算机计算机之间通过网络进行数据传输。

  • Java中可以使用Java.net包下的技术轻松开发出常见的网络应用程序。

常见的软件架构:

BS:Browser/Server 浏览器/服务器

只需要一个浏览器,用户提供不同的网址。客户访问不同的服务器。

优缺点:

  • 不需要开发客户端,只需要页面+服务端

  • 用户不需要下载,打开浏览器就能使用

  • 如果应用过大,用户体验受到影响

CS:Client/S2erver 客户端/服务器

用户本地想要下载并安装客户端程序,在远程有一个服务器端程序。

优缺点:

服务器就不需要将图片、音乐等等资源发送给客户端,客户端已经下载,只需要告诉客户端该显示什么资源了。

  • 画面可以做的非常精美,用户体验好

  • 需要开发客户端、也需要开发服务端

  • 用户需要下载和更新的时候太麻烦

网络编程三要素

IP(Internet Protocol)

是互联网协议地址,也称IP地址。分配给上网设备的数字标签

  • 上网设备在网络中的地址,是唯一的标识

常见的IP分类为:IPv4、IPv6

IPv4:互联网通信协议第四版

目前主流

采用32位地址长度,分为4组

最多只有2的32次方个IP,目前以使用完

IPv4的地址分类形式
  • 公网地址(万维网使用)和私有地址(局域网使用)

  • 192.168.开头的就是私有地址,范围即为192.168.0.0--192.168.255.255,专门为组织机构内部使用,以此节省IP

特殊的IP地址

127.0.0.1,也可以是localhost:是回送地址也称本地回环地址,也称本机IP,永远只会寻找当前所在本机。

IPv6:互联网通信协议第六版

解决IPv4不够用的问题

采用128位地址长度,分为8组,采用,冒分十六进制表示法

最多有2的128次方个IP,可以给地球上每个沙子一个IP。

常用的CMD命令

  • ipconfig:查看本机IP地址

  • ping:检查网络是否连通

InetAddress使用

此类表示互联网协议(IP)地址

没有构造方法,不能直接new,用静态方法getbyname

package com.cg;
​
import java.net.InetAddress;
import java.net.UnknownHostException;
​
public class MyInetAddressDemo {
​
    public static void main(String[] args) throws UnknownHostException {
        /*
        * static InetAddress getByName(String host) 根据主机名确定主机的 IP 地址。 主机名可以是机器名称,也可以是IP地址
        * String getHostAddress() 以文本形式返回 IP 地址字符串。
        * String getHostName() 获取此 IP 地址的主机名。
        * */
​
        //1、获取InetAddress的对象
        //address IP的对象 一台电脑的对象
        InetAddress indexAddress = InetAddress.getByName("192.168.1.100");
        System.out.println(indexAddress);
​
        InetAddress address = InetAddress.getByName("薄荷");
        System.out.println(address);
​
        String name = address.getHostName();
        System.out.println(name);//薄荷
​
        String ip = address.getHostAddress();
        System.out.println(ip); //192.168.140.1
​
    }
}
——————————————————————————————————————————
/192.168.1.100
薄荷/192.168.140.1
薄荷
192.168.140.1
 

这是一个前置的代码,获取到某一台电脑对象之后,就可以给这台电脑发送信息

端口号

  • 应用程序在设备中唯一的标识

端口号:由两个字节表示的整数,取值范围:0~65535

其中0~1023之间的端口号用于一些知名的网络服务或者应用。

我们自己使用1024以上的端口号就可以了。

注意:一个端口号只能被一个应用程序使用

协议

计算机网络中,连接和通信的规则被称为网络通信协议

  • 数据在网络中传输的规则,常见的协议有:UDP、TCP、http、https、ftp。

  • OSI参考模型:世界互联协议标准,全国通信规范,单模型过于理想化,未能在因特网上进行广泛推广

  • TCP/IP参考模型(或TCP/IP协议):事实上的国际标准。

OSI参考模型
应用层
表示层
会话层
传输层
网络层
数据链路层
物理层

例如:在自己电脑将一条信息一层一层的往下,在物理层将数据转换成二进制,然后传输给其他电脑的物理层在解析,一层一层的往上达到应用层。

太理想化,太复杂

TCP/IP参考模型TCP/IP参考模型各层对应协议面向那些
应用层HTTP、FTP、Telnet、DNS....一般是应用程序需要关注的。如浏览器,邮箱。程序员一般在这一层开发。
传输层TCP、UDP、.....选择传输使用的TCP,UDP协议
网络层IP、ICMP、ARP、.....封装自己的IP,对方的IP等信息
物理(+数据)链路层硬件设备。010100101010100101010.....转换成二进制利用物理设备传输

UDP协议

  • 用户数据报协议(User DATagram Protocol)

  • UDP是面向无连接通信协议。

    速度快,有大小限制一次最多发送64K,数据不安全,易丢失数据

不管设备是否已经连接成功

都会发送消息,能收到就收到,收不到就算了

应用场景

网络会议、语音通话、在线视频

发送数据
  1. 创建发送端的DATagramSocket对象

  2. 数据打包(DatagramPacket)

  3. 发送数据

  4. 释放资源

package com.cg;
​
import java.io.IOException;
import java.net.*;
​
public class SendMessageDemo {
​
    public static void main(String[] args) throws IOException {
        //发送数据
​
        //1、创建DATagramSocket对象  (快递公司)
        //细节:
        //绑定对应的端口,以后我们就是通过这个端口往外发送
        //空参:所有可用的端口中随机一个进行使用
        //有参:指定端口号进行绑定
        DatagramSocket ds = new DatagramSocket();
​
        //2、打包数据
        String str = "你好呀微";
        byte[] bytes = str.getBytes();
        InetAddress address = InetAddress.getByName("127.0.0.1");
        int  port = 10086;
​
        DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length,address,port);
​
        //3、发送数据
        ds.send(datagramPacket);
​
        //4、释放资源
        ds.close();
    }
}
​

接收数据
  1. 创建接收端的DatagramSocket对象

  2. 接收打包好的数据

  3. 解析数据包

  4. 释放资源

package com.cg;
​
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
​
public class ReceiveMessageDemo {
​
    public static void main(String[] args) throws IOException {
        //接收数据
​
        //1、创建DATagramSocket对象  (快递公司)
        //细节:
        //在接收的时候一定要绑定端口
        //而且绑定的端口一定要和发送的端口保持一致
        DatagramSocket ds = new DatagramSocket(10086);
​
        //2、接收数据包
        byte[] bytes = new byte[1024];
        DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length);
​
        //该方法是阻塞的
        //程序执行到这一步的时候,会在这里死等
        //等发送端发送消息
        ds.receive(datagramPacket);
​
        //3、解析数据包
        byte[] data = datagramPacket.getData();
        int length = datagramPacket.getLength();
        InetAddress address = datagramPacket.getAddress();
        int port = datagramPacket.getPort();
​
        System.out.println("接收到数据"+new String(data,0,length));
        System.out.println("该数据是从"+address+"这台电脑中的"+port+"这个端口号发出的");
​
        //4、释放资源
        ds.close();
    }
}
​
——————————————————————————————————————————————————————————————————————————
接收到数据你好呀微
该数据是从/127.0.0.1这台电脑中的63035这个端口号发出的
​

  • 按照下面的要求实现程序

    • UDP发送数据: 数据来自于键盘录入,直到输入的数据是886,发送数据结束

    • UDP接收数据: 因为接收端不知道发送端什么时候停止发送,故采用死循环接收

package com.cg;
​
import java.io.IOException;
import java.net.*;
import java.util.Scanner;
​
public class SendMessageDemo {
​
    public static void main(String[] args) throws IOException {
        //1、创建DATagramSocket对象
        DatagramSocket ds = new DatagramSocket();
​
        //2、打包数据
        Scanner scan = new Scanner(System.in);
​
        while (true) { //ctrl+alt+T
            System.out.println("请输入您要说的话:");
            String str = scan.nextLine();
            if ("886".equals(str)){
                break;
            }
            byte[] bytes = str.getBytes();
​
            InetAddress address = InetAddress.getByName("127.0.0.1");
            //改为255.255.255.255 在发送的时候就可以给局域网里所有的电脑发送
            int  port = 10086;
​
            DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length,address,port);
​
            //3、发送数据
            ds.send(datagramPacket);
        }
​
        //4、释放资源
        ds.close();
    }
}
package com.cg;
​
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
​
public class ReceiveMessageDemo {
​
    public static void main(String[] args) throws IOException {
        //1、创建DATagramSocket对象
        DatagramSocket ds = new DatagramSocket(10086);
​
        //2、接收数据包
        byte[] bytes = new byte[1024];
        DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length);
​
        while (true) {
            ds.receive(datagramPacket);
​
            //3、解析数据包
            byte[] data = datagramPacket.getData();
            int length = datagramPacket.getLength();
            String ip = datagramPacket.getAddress().getHostAddress();
            String name = datagramPacket.getAddress().getHostName();
​
            //4、打印数据
            System.out.println("ip为"+ip+",主机名为:"+name+"的人,发送了数据:"+new String(data,0,length));
        }
    }
}

实现多个发送端发送消息:

点击 Edit Configurations.....

选中发送端程序 点击 Modify options

选择 Allow multiple instances


三种通信方式
单播

一对一

之前写的代码就是单播

组播

一台电脑可以给一组电脑发送数据

组播地址:224.0.0.0~239.255.255.255

其中224.0.0.0~224.0.0.255为预留的组播地址

代码实现
package com.cg.demo;
​
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
​
public class SendMessageDemo {
​
    public static void main(String[] args) throws IOException {
        /*
         * 组播发送端代码
         * */
        //创建MulticastSocket对象
        MulticastSocket multicastSocket = new MulticastSocket();
​
        //创建DatagramPacket对象
        String str = "你好,你好";
        byte[] bytes = str.getBytes();
        InetAddress address = InetAddress.getByName("224.0.0.1");
        int port = 10000;
​
        DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length,address,port);
​
        //发送数据
        multicastSocket.send(datagramPacket);
        //释放资源
        multicastSocket.close();
    }
}
package com.cg.demo;
​
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
​
public class ReceiveMessageDemo1 {
​
    public static void main(String[] args) throws IOException {
        /*
         * 组播接收端代码
         * */
        //1、创建MulticastSocket对象
        MulticastSocket multicastSocket = new MulticastSocket(10000);
​
        //2、将当前本机,添加到224.0.0.1的这一组当中
        InetAddress address = InetAddress.getByName("224.0.0.1");
        multicastSocket.joinGroup(address);
​
        //3、创建DatagramPacket 数据包对象
        byte[] bytes = new byte[1024];
        DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length);
​
        //4、接收数据
        multicastSocket.receive(datagramPacket);
​
        //5、解析数据
        byte[] data = datagramPacket.getData();
        int length = datagramPacket.getLength();
        String ip = datagramPacket.getAddress().getHostAddress();
        String name = datagramPacket.getAddress().getHostName();
​
        System.out.println("ip为"+ip+",主机名为:"+name+"的人,发送了数据:"+new String(data,0,length));
​
        //6、释放资源
        multicastSocket.close();
    }
}   
package com.cg.demo;
​
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
​
public class ReceiveMessageDemo2 {
​
    public static void main(String[] args) throws IOException {
        /*
         * 组播接收端代码
         * */
​
        //1、创建MulticastSocket对象
        MulticastSocket multicastSocket = new MulticastSocket(10000);
​
        //2、将当前本机,添加到224.0.0.1的这一组当中
        InetAddress address = InetAddress.getByName("224.0.0.1");
        multicastSocket.joinGroup(address);
​
        //3、创建DatagramPacket 数据包对象
        byte[] bytes = new byte[1024];
        DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length);
​
        //4、接收数据
        multicastSocket.receive(datagramPacket);
​
        //5、解析数据
        byte[] data = datagramPacket.getData();
        int length = datagramPacket.getLength();
        String ip = datagramPacket.getAddress().getHostAddress();
        String name = datagramPacket.getAddress().getHostName();
​
        System.out.println("ip为"+ip+",主机名为:"+name+"的人,发送了数据:"+new String(data,0,length));
​
        //6、释放资源
        multicastSocket.close();
    }
}
package com.cg.demo;
​
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
​
public class ReceiveMessageDemo3 {
​
    public static void main(String[] args) throws IOException {
        /*
         * 组播接收端代码
         * */
​
        //1、创建MulticastSocket对象
        MulticastSocket multicastSocket = new MulticastSocket(10000);
​
        //2、将当前本机,添加到224.0.0.1的这一组当中
        InetAddress address = InetAddress.getByName("224.0.0.1");
        multicastSocket.joinGroup(address);
​
        //3、创建DatagramPacket 数据包对象
        byte[] bytes = new byte[1024];
        DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length);
​
        //4、接收数据
        multicastSocket.receive(datagramPacket);
​
        //5、解析数据
        byte[] data = datagramPacket.getData();
        int length = datagramPacket.getLength();
        String ip = datagramPacket.getAddress().getHostAddress();
        String name = datagramPacket.getAddress().getHostName();
​
        System.out.println("ip为"+ip+",主机名为:"+name+"的人,发送了数据:"+new String(data,0,length));
​
        //6、释放资源
        multicastSocket.close();
    }
}

广播

一台电脑可以给局域网中所有的电脑发送数据

广播地址:255.255.255.255

代码实现
package com.cg;
​
import java.io.IOException;
import java.net.*;
import java.util.Scanner;
​
public class SendMessageDemo {
​
    public static void main(String[] args) throws IOException {
        //1、创建DATagramSocket对象
        DatagramSocket ds = new DatagramSocket();
​
        //2、打包数据
        Scanner scan = new Scanner(System.in);
​
        while (true) { //ctrl+alt+T
            System.out.println("请输入您要说的话:");
            String str = scan.nextLine();
            if ("886".equals(str)){
                break;
            }
            byte[] bytes = str.getBytes();
​
            InetAddress address = InetAddress.getByName("255.255.255.255");
            //改为255.255.255.255 在发送的时候就可以给局域网里所有的电脑发送
            int  port = 10086;
​
            DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length,address,port);
​
            //3、发送数据
            ds.send(datagramPacket);
        }
​
        //4、释放资源
        ds.close();
    }
}
package com.cg;
​
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
​
public class ReceiveMessageDemo {
​
    public static void main(String[] args) throws IOException {
        //1、创建DATagramSocket对象
        DatagramSocket ds = new DatagramSocket(10086);
​
        //2、接收数据包
        byte[] bytes = new byte[1024];
        DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length);
​
        while (true) {
            ds.receive(datagramPacket);
​
            //3、解析数据包
            byte[] data = datagramPacket.getData();
            int length = datagramPacket.getLength();
            String ip = datagramPacket.getAddress().getHostAddress();
            String name = datagramPacket.getAddress().getHostName();
​
            //4、打印数据
            System.out.println("ip为"+ip+",主机名为:"+name+"的人,发送了数据:"+new String(data,0,length));
        }
    }
}

TCP协议

  • 传输控制协议TCP(Transmission Control Protocol)

  • TCP协议是面向连通的通信协议

    速度慢,没有大小限制,数据安全

TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象

通信前确保连接成功,才会发送数据

通过Socket产生的IO流来进行网络通信

应用场景

下载软件,文字聊天,发送邮件

实现
客户端(Socket)
  1. 创建客户端的Socket对象(Socket)与指定服务端连接

    Socket(String host,int port)

  2. 获取输出流,写数据

    OutputStream getOutputStream()

  3. 释放资源

        void close()

package com.cg.demo2;
​
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
​
public class Client {
    public static void main(String[] args) throws IOException {
        //TCP协议,发送数据
​
        //1、创建Socket对象
        //细节:在创建对象的同时会连接服务器
        //      如果连接不上,代码会报错
        Socket socket = new Socket("127.0.0.1",10086);
​
        //2、可以从连接通道中获取输出流
        OutputStream os = socket.getOutputStream();
        //写出数据
        os.write("你好你好".getBytes());
​
        //3、释放资源
        os.close();
        socket.close();
    }
}

服务器(ServerSocket)
  1. 创建服务器的Socket对象(ServerSocket)

    ServerSocket(int port) (端口号与客户端保持一致)

  2. 监听客户端连接,返回一个Socket对象

    Socket accept()

  3. 获取输入流,读数据,并把数据显示在控制台

    InputStream getInputStream()

  4. 释放资源

        void close()

package com.cg.demo2;
​
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
​
public class Server {
​
    public static void main(String[] args) throws IOException {
        //TCP协议 接收数据
​
        //1、创建ServerSocket对象
        ServerSocket serverSocket = new ServerSocket(10086);
​
        //2、监听客户端的连接
        Socket socket = serverSocket.accept();
​
        //3、从连接通道中获取输入流读取数据
        InputStream inputStream = socket.getInputStream();
        int b;
        while ((b = inputStream.read()) != -1){
            System.out.println((char) b);
        }
​
        //4、释放资源
        socket.close();
        serverSocket.close();
    }
}
​
___________________________________________________________
    传中文会乱码
ä
½
 
å
¥
½
ä
½
 
å
¥
½
​

中文乱码问题

产生乱码原因:

没有指定编码表,会使用平台,默认的编码表 UTF-8

修改服务端

package com.cg.demo2;
​
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
​
public class Server {
​
    public static void main(String[] args) throws IOException {
        //TCP协议 接收数据
​
        //1、创建ServerSocket对象
        ServerSocket serverSocket = new ServerSocket(10086);
​
        //2、监听客户端的连接
        Socket socket = serverSocket.accept();
​
        //3、从连接通道中获取输入流读取数据
//        InputStream inputStream = socket.getInputStream();//字节流 一个字节一个字节的读
//        //转换流         转换为字符流
//        InputStreamReader reader = new InputStreamReader(inputStream);
//        //想提高读取的效率    缓冲流
//        BufferedReader bufferedReader = new BufferedReader(reader);
        
        //更简单
        BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(socket.getInputStream()));
        
        int b;
        while ((b = bufferedReader.read()) != -1){
            System.out.print((char) b);
        }
​
        //4、释放资源
        socket.close();
        serverSocket.close();
    }
}

三次握手

协议保证连接建立

客户端 ———客户端向服务器发送连接请求 等待服务器确认 ———>服务器

客户端 <———服务器向客户端返回一个响应 告诉客户端收到请求 ———服务端

客户端 ———客户端向服务器再次发出确认信息 连接建立 ———>服务端

四次挥手

利用这个协议断开连接

而且保证连接通道里面的数据已经处理完毕了

确保连接断开,且数据处理完毕

客户端 ———   客户端向服务器发出取消连接请求                                 ———>服务器

客户端 <——— 服务器向客户端返回一个响应 表示收到客户端取消请求 ———服务器

                                                                                                                                |

                                                                                                        服务器将最后的数据处理完毕

                                                                                                                                 |

客户端 <———  服务器向客户端发出确认取消信息                                ———服务器

客户端 ———   客户端再次发送确认消息 连接取消                               ———>服务器

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值