08- 网络编程

网络编程基础

认识网络

网络概述

网络 就是 连接在一起 共享数据和资源的一组计算机

网络分类

个人区域网络
局域网
	指在某一区域内由多台计算机互联成的计算机组。一般是方圆几千米以内。局域网可以实现文件管理、应用软件共享、打印机共享、工作组内的日程安排、电子邮件和传真通信服务等功能。局域网是封闭型的,可以由办公室内的两台计算机组成,也可以由一个公司内的上千台计算机组成。
城域网
	在一个城市范围内所建立的计算机通信网,简称MAN。属宽带局域网。由于采用具有有源交换元件的局域网技术,网中传输时延较小,它的传输媒介主要采用光缆,传输速率在100兆比特/秒以上。
广域网
	又称广域网、外网、公网。是连接不同地区局域网或城域网计算机通信的远程网。通常跨接很大的物理范围,所覆盖的范围从几十公里到几千公里,它能连接多个地区、城市和国家,或横跨几个洲并能提供远距离通信,形成国际性的远程网络。广域网并不等同于互联网。

网络分层模型

在这里插入图片描述

数据传输原理

在这里插入图片描述

每一层的功能

OSITCP/IP协议
应用层应用层HTTP, HTTPS , SSH , POP,FTP,DNS…
表示层/会话层/传输层传输层TCP, UDP…
网络层网络层ARP, IPV4, IPV6, ICMP…
数据链路层/物理层网络接口层以太网,无线LAN,PPP…
1- 分层优点:协议分层就如同计算机软件中的模块化开发。OSI参考模型的建议是比较理想化的,它希望实现从第一层到第七层的所有模块,并将它们组合起来实现网络通信。分层可以将每个分层独立使用即使系统中某些分层发生变化,也不会波及整个系统。因此,可以构造一个扩展性和灵活性都较强的系统。此外,通过分层能够细分通信功能,更易于单独实现每个分层的协议,并界定各个分层的具体责任和义务。
2- 分层缺点:过于模块化,使处理就得更加沉重以及每个模块都不得不实现相似的处理逻辑等问题。

每层功能简述

1) 物理层:主要定义物理设备标准,如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。它的主要作用是传输比特流(就是由1、0转化为电流强弱来进行传输,到达目的地后再转化为1、0,也就是我们常说的数模转换与模数转换)。这一层的数据叫做比特。
2)数据链路层:定义了如何让格式化数据以帧为单位进行传输,以及如何让控制对物理介质的访问。这一层通常还提供错误检测和纠正,以确保数据的可靠传输。如:串口通信中使用到的115200、8、N、1
3)网络层:在位于不同地理位置的网络中的两个主机系统之间提供连接和路径选择。Internet的发展使得从世界各站点访问信息的用户数大大增加,而网络层正是管理这种连接的层。
4) 传输层:定义了一些传输数据的协议和端口号(WWW端口80等),如:TCP(传输控制协议,传输效率低,可靠性强,用于传输可靠性要求高,数据量大的数据),UDP(用户数据报协议,与TCP特性恰恰相反,用于传输可靠性要求不高,数据量小的数据,如QQ聊天数据就是通过这种方式传输的)。 主要是将从下层接收的数据进行分段和传输,到达目的地址后再进行重组。常常把这一层数据叫做段。
5) 会话层:通过传输层(端口号:传输端口接收端口)建立数据传输的通路。主要在你的系统之间发起会话或者接受会话请求(设备之间需要互相认识可以是IP也可以是MAC或者是主机名)。
6)表示层:可确保一个系统的应用层所发送的信息可以被另一个系统的应用层读取。例如,PC程序与另一台计算机进行通信,其中一台计算机使用扩展二一十进制交换码(EBCDIC),而另一台则使用美国信息交换标准码(ASCII)来表示相同的字符。如有必要,表示层会通过使用一种通格式来实现多种数据格式之间的转换。
7) 应用层:是最靠近用户的OSI层。这一层为用户的应用程序(例如电子邮件、文件传输和终端仿真)提供网络服务。

网络编程三要素

协议

为了在网络中 不同的计算机之间进行通讯而建立的规则. 标准.或约定的集合,

它规定了网络通讯时, 数据必须采用的格式以及这些格式的意义

贺卡
写信  邮编  收信人  寄信人 
	当用户收到该信件的时候, 语言上也需要统一
传输层协议

TCP/IP协议族 是一个 协议族

Integer 标准协议 , 包含  IP协议, TCP协议 ,UDP协议 
TCP协议
1- 面向连接的,
2- 可靠的,
3- 基于字节流的 
4- 点对点的 传输层的协议
UDP协议
1- 无连接的
2- 不保证安全的
3- 支持一对一, 一对多, 多对多的
4- 没有拥塞控制, 内部开销少的 传输层协议
TCP 建立连接的三次握手协议

在这里插入图片描述

第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。

第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;

第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。

TCP 关闭连接的四次挥手协议

在这里插入图片描述

第一次握手 
    TCP发送一个FIN(结束),用来关闭客户到服务端的连接。
    客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),
此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。

第二次握手
    服务端收到这个FIN,他发回一个ACK(确认),确认收到序号为收到序号+1,和SYN一样,一个FIN将占用一个序号。
    服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器
通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
	客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。

第三次握手
      服务端发送一个FIN(结束)到客户端,服务端关闭客户端的连接。
      服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,

此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。

第四次握手
     客户端发送ACK(确认)报文确认,并将确认的序号+1,这样关闭完成。
     客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时
TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。
网友理解三次握手
	TCP 三次握手好比在一个夜高风黑的夜晚,你一个人在小区里散步,不远处看见小区里的一位漂亮妹子迎面而来,但是因为路灯有点暗等原因不能100%确认,所以要通过招手的方式来确定对方是否认识自己。
	你首先向妹子招手(syn),妹子看到你向自己招手后,向你点了点头挤出了一个微笑(ack)。你看到妹子微笑后确认了妹子成功辨认出了自己(进入estalished状态)。
	但是妹子有点不好意思,向四周看了一看,有没有可能你是在看别人呢,她也需要确认一下。妹子也向你招了招手(syn),你看到妹子向自己招手后知道对方是在寻求自己的确认,于是也点了点头挤出了微笑(ack),妹子看到对方的微笑后确认了你就是在向自己打招呼(进入established状态)。
	于是两人加快步伐,走到了一起,彼此之间相互拥抱。
	我们来回顾一下,这个过程中总共有四个动作,
1- 你招手
2- 妹子点头微笑
3- 妹子招手
4- 你点头微笑
	其中妹子连续进行了两个动作,先是点头微笑(回复对方),然后再次招手(寻求确认),实际上我们可以将这两个动作合成一个动作,招手的同时点头和微笑(syn+ack)。于是这四个动作就简化成了三个动作。
1- 你招手
2- 妹子点头微笑并招手
3- 你点头微笑
这就是三次握手的本质,中间的一次动作是两个动作的合并。通过这个案例,不知你对TCP三次握手,有没有进一步的理解。

握手完成后,开始TCP 数据传输
TCP 数据传输就是两个人隔空交流,有一定的距离,需要对方反复确认听见了自己的话。

你喊了一句话(data),妹子听见了之后要向你回复自己听见了(ack)。如果你喊了一句,半天没听到妹子回复,你会很低落,好比谈恋爱的时候,你满腔热情,而妹子忽冷忽热,所以你锲而不舍,一次不行,就两次,两次不行就三次,这就是tcp重传。

	也有可能是妹子知道你的本意了,但是妹子有点害羞,迟迟没有回复亦或是妹子回复了你没收到,以至于你没收到妹子的回复。你不能判断究竟到底妹子喜不喜欢你,对你有没有好感,没关系,男人嘛?要主动点,重传一下就好。

	既然会重传,妹子就有可能同一句话听见了两次,这就是去重。对于重传和去重这两项工作操作系统的网络内核模块都已经帮我们处理好了,我们不用理会。

	由于笔者水平有限,由于笔者水平有限,很多网络基础知识需要去深入了解去探索,文中纰漏之处在所难免,权当抛砖引玉,还请各位大牛不吝赐教。欢迎交流。
--------------------- 
原文链接:https://blog.csdn.net/X8i0Bev/article/details/83066876

IP地址

概念
在网络中使用一种具有层次结构的逻辑地址来标识一台主机, 该地址成为IP地址
组成
IPv4 地址有32位 , 是由4个8位的二进制数组成, 因为二进制可读性较差, 所以一般使用10进制表示
IPv6 地址有128位  由8个16进制的无符号整数表示, 每个整数有4个16进制数表示 3ffe:*8
分类

网络地址 + 主机地址

网络地址决定了可以分配的最大的网络数

主机地址决定了在一个网络中可以存在的计算机的最大数量

IP分类号段一个号段对应的主机数
A类1个网络 + 3 个主机号段256*256*256-2
B类2个网络 + 2 个主机号段256*256-2
C类3个网络 + 1 个主机号段256-2
D类E类
减2 的原因 
主机号段 二进制为全为0,表示本机
主机号段 二进制为全为1,表示本网段全部主机

两个特殊地址

0.0.0.0 本机

127.0.0.1 本机回环地址 ,

255.255.255.255 一般表示当前子网

IP地址的配置和检测

两个DOS 命令

ipconfig	查看本机IP地址, 子网掩码, 默认网关等信息
ping	测试网络是否通畅

修改IP地址

控制面板==> 网络和共享中心==> 当前网络点击/右键属性 > 属性> IPv4版本

端口号

万维网 www 通过(统一资源定位符 URL )标识 网络中的各种资源

URL 的格式 协议:// IP地址:端口/资源路径和名称

设备与外界通讯交流的出口 , 每一个进程都有一个唯一的端口号

其他概念

服务器

在网络环境下, 具有较高计算能力, 能够为用户提供特殊服务功能的计算机

服务器本质上就是一个能提供特殊服务功能的应用程序

邮件服务器
web服务器

也称之为 www 服务器, 主要功能是提供网上信息浏览服务

Apache服务器
Tomcat服务器

DNS 服务器

域名

域名(英语:Domain Name),简称域名网域,是由一串用点分隔的名字组成的Internet上某一台计算机或计算机组的名称,用于在数据传输时标识计算机的电子方位(有时也指地理位置)。 取代IP地址 不方便阅读的弊端

DNS服务器 专门存储 域名和IP地址之间的映射关系

本地DNS

计算机本地也有 映射关系的 DNS

C:\Windows\System32\drivers\etc

hosts 文件

127.0.0.1       localhost

所有使用 本机的IP的地方 可以使用 localhost 来代替

Socket 编程

Socket 概念

两台计算机通过网络通信连接实现数据的交换, 把通信链路的端点称之为"套接字"(Socket)

使用物流收送快递, 用户只需要把写有详细收件人信息的货物送到快递站, 配送过程, 用户无需了解, 只需要知道结果就可以了

通讯原理

Socket 是网络驱动层, 提供给应用程序的一种机制, 对于编程人员来说, 无需知道Socket 底层是如何传送数据的, 而是直接将数据提交给Socket . Socket 会根据相关信息, 自动提交数据.

Socket 的底层机制相当复杂, Java平台提供了一些常用的类, 以便于更加简单有效的使用Socket

基于TCP 协议的 Socket 编程

两个常用类

java.net

Socket

在客户端和服务器之间建立连接, 可以使用该类的构造方法创建套接字对象, (相当于快递包裹)

需要指定 接收人的姓名 地址, (在网络中 ,需要通过IP地址 和 端口号指向一个主机服务器)

方法名说明
InetAddress getInetAddress()
int getPort()
int getLocalPort()
InputStream getInputStream()
OutputStream getOutputStream()
void close()

ServerSocket

服务器端, 等待客户端建立连接

构造方法

通过端口号建立 对象, 监听此端口号

常用方法

对象.accept() 等待连接 , 开始监听

案例

案例一

简单消息单次发送

客户端

package s0806.socket;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;

/**
 * 客户端发送信息服务器端
 */
public class Client {
    public static void main(String[] args) throws IOException {
        // 建立客户端到服务器的连接
        // 1- 收件人姓名和地址
        Socket socket = new Socket("localhost",8888);
        // 使用 socket 获取一个输出流
        // 2- 书信中要书写的东西
        OutputStream os = socket.getOutputStream();
        // 使用输出流 向 localhost 地址的 8888 端口号输出信息
        String s = "身在远方的你,现在还好吗? ";
        System.out.println("在中国向外发送信息...");
        os.write(s.getBytes());
        // 输出流 关闭
        socket.shutdownOutput();
    }
}

服务器端

package s0806.socket;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
 * 服务器端 接收数据
 */
public class Server {
    public static void main(String[] args) throws IOException {
        // 设置 服务器端 监听他的端口
        ServerSocket server = new ServerSocket(8888);
        // 开启监听, 一旦发现有客户端来连接 , 返回该客户端套接字
        Socket client = server.accept();
        // 使用输入流 获取信息
        InputStream is = client.getInputStream();

        // 使用IO流 输入流 获取字符串信息 比较麻烦 包装包装流
        // 转环流 字节==> 字符流
        InputStreamReader isr = new InputStreamReader(is);
        BufferedReader br = new BufferedReader(isr);
        String s;
        while( (s = br.readLine()) != null ){
            System.out.println("美国--"+s);
        }
        br.close();

    }
}

案例二

完成 用户循环输入自定义代码 到服务器

客户端

package s0806.socket1;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

/**
 * 客户端发送信息服务器端
 */
public class Client {
    public static void main(String[] args) throws IOException {
        Scanner input = new Scanner(System.in);
        while(true){
        // 建立客户端到服务器的连接
        Socket socket = new Socket("localhost",8887);
        // 使用 socket 获取一个输出流
          OutputStream os = socket.getOutputStream();
          // 使用输出流 向 localhost 地址的 8888 端口号输出信息
          // 键盘录入功能
          System.out.print("客户端说:");
          String s = input.nextLine();
          os.write(s.getBytes());
          os.close();
      }
    }
}

服务器

package s0806.socket1;

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 {
        // 设置 服务器端 监听他的端口
        ServerSocket server = new ServerSocket(8887);
        // 开启监听, 一旦发现有客户端来连接 , 返回该客户端套接字
        while(true){
            Socket client = server.accept();
            // 使用输入流 获取信息
            InputStream is = client.getInputStream();

            // 使用IO流 输入流 获取字符串信息 比较麻烦 包装包装流
            // 转环流 字节==> 字符流
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);
            String s;
            while( (s = br.readLine()) != null ){
                System.out.println("服务器端--"+s);
            }
            br.close();
        }
    }
}

案例三

双方都可以 接收和发送数据, 使用多线程完成

服务器端线程 ReceiveRunnable

package s0806.socket2;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

public class ReceiveRunnable implements  Runnable{
    private String name;
    int port ;
    public ReceiveRunnable(String name , int port) {
        this.name = name;
        this.port = port;
    }
    @Override
    public void run() {
        try {
            // 设置 服务器端 监听他的端口
            ServerSocket server = new ServerSocket(port);
            // 开启监听, 一旦发现有客户端来连接 , 返回该客户端套接字
            while(true) {
                Socket client = server.accept();
                // 使用输入流 获取信息
                InputStream is = client.getInputStream();

                // 使用IO流 输入流 获取字符串信息 比较麻烦 包装包装流
                // 转环流 字节==> 字符流
                InputStreamReader isr = new InputStreamReader(is);
                BufferedReader br = new BufferedReader(isr);
                String s;
                while ((s = br.readLine()) != null) {
                    System.out.println(name+"--" + s);
                }
                br.close();
            }
        }catch(Exception e){
            // 打印 堆栈信息异常
            e.printStackTrace();
        }
    }
}

客户端线程 SendRunnable

package s0806.socket2;


import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class SendRunnable implements  Runnable{
    private String name;
    int port ;
    public SendRunnable(String name , int port) {
        this.name = name;
        this.port = port;
    }
    @Override
    public void run() {
        try {
            Scanner input = new Scanner(System.in);
            while(true){
                // 建立客户端到服务器的连接
                Socket socket = new Socket("localhost",port);
                // 使用 socket 获取一个输出流
                OutputStream os = socket.getOutputStream();
                // 使用输出流 向 localhost 地址的 8888 端口号输出信息
                // 键盘录入功能
                System.out.print(name+"--");
                String s = input.nextLine();
                os.write(s.getBytes());
                os.close();
            }
        }catch(Exception e){
            // 打印 堆栈信息异常
            e.printStackTrace();
        }
    }
}

测试张三

package s0806.socket2;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 客户端发送信息服务器端
 */
public class Client {
    public static void main(String[] args) throws IOException, InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.submit(new ReceiveRunnable("张三",10010));
        Thread.sleep(5000);
        executorService.submit(new SendRunnable("张三",10086));
    }
}

测试李四

package s0806.socket2;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 服务器端 接收数据
 */
public class Server {
    public static void main(String[] args) throws IOException, InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.submit(new ReceiveRunnable("李四",10086));
        Thread.sleep(5000);
        executorService.submit(new SendRunnable("李四",10010));
    }
}

案例四

从客户端 向服务器 传递一个 对象

Student

package s0806.socket;
import java.io.Serializable;

// 序列化
public class Student implements Serializable {
    String name;
    int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

客户端

package s0806.socket;

import java.io.IOException;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
/**
 * 客户端发送信息服务器端
 */
public class Client {
    public static void main(String[] args) throws IOException {
        // 建立客户端到服务器的连接
        Socket socket = new Socket("localhost",8888);
        // 使用 socket 获取一个输出流
        OutputStream os = socket.getOutputStream();
        // 使用输出流 向 localhost 地址的 8888 端口号输出信息
        // 把输出流 转换为序列化流
        ObjectOutputStream  oos = new ObjectOutputStream(os);
        oos.writeObject(new Student("张胜男",20));
        // 输出流 关闭
        socket.shutdownOutput();
    }
}

服务器

package s0806.socket;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
 * 服务器端 接收数据
 */
public class Server {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // 设置 服务器端 监听他的端口
        ServerSocket server = new ServerSocket(8888);
        // 开启监听, 一旦发现有客户端来连接 , 返回该客户端套接字
        Socket client = server.accept();
        // 使用输入流 获取信息
        InputStream is = client.getInputStream();
        
        // 包装为序列化流
        ObjectInputStream ois = new ObjectInputStream(is);
        Object o = ois.readObject();
        Student stu = (Student)o;
        System.out.println(stu.name);
        ois.close();
    }
}

基于UDP 协议的 Socket编程

数据报

数据报, 通讯的一种报文类型, 使用数据报进行通信, 无需事先建立连接

两个UDP常用类

DatagramPacket

构造方法

构造方法
DatagramPacket(byte[] buf, int length, InetAddress address, int port)构造用于发送长度的分组的数据报包 length指定主机上到指定的端口号。
DatagramPacket(byte[] buf, int length)构造一个 DatagramPacket用于接收长度的数据包 length

成员方法

成员方法
InetAddress``getAddress()返回该数据报发送或接收数据报的计算机的IP地址。
byte[]``getData()返回数据缓冲区。
int``getLength()返回要发送的数据的长度或接收到的数据的长度。
int``getPort()返回发送数据报的远程主机上的端口号,或从中接收数据报的端口号。

DatagramSocket

  • 此类表示用于发送和接收数据报数据包的套接字。
构造方法
构造方法
DatagramSocket()构造数据报套接字并将其绑定到本地主机上的任何可用端口。
DatagramSocket(int port)构造数据报套接字并将其绑定到本地主机上的指定端口。
常用方法
常用方法
void``connect(InetAddress address, int port)将套接字连接到此套接字的远程地址。
void``close()关闭此数据报套接字。
void``disconnect()断开插座。
InetAddress``getInetAddress()返回此套接字连接到的地址。
int``getLocalPort()返回此套接字绑定到的本地主机上的端口号。
int``getPort()返回此套接字连接到的端口号。
void``send(DatagramPacket p)从此套接字发送数据报包。
void``receive(DatagramPacket p)从此套接字接收数据报包。

使用Socket 完成 客户咨询

主要步骤

1- 使用DatagramPacket  封装数据包
2- 使用DatagramSocket  发送数据包
3- 使用DatagramSocket  接收数据包
4- 使用DatagramPacket  解析数据包

代码实现

客户案例代码

package s0807;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class Send {
    public static void main(String[] args) throws Exception {
        // 填写 收件人信息
        InetAddress ia = InetAddress.getByName("localhost");
        // 包裹内容
        String mess = "给女朋友发红包的日子, 又来了!!";
        byte[] bys = mess.getBytes();
        // 1- 封装一个包裹
        /**
         * 四个参数
         */
        DatagramPacket dp = new DatagramPacket(bys,bys.length,ia,10086);
        //  发送包裹
        DatagramSocket ds = new DatagramSocket();
        ds.send(dp);
        // 关闭资源包
        ds.close();
    }
}

平台代码

package s0807;

import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class Receive {
    public static void main(String[] args) throws Exception {
        // 新建包裹 用于接收内容
        byte bys[] = new byte[1024];
        DatagramPacket dp = new DatagramPacket(bys,1024);

        // 新建监听包裹的套接字
        DatagramSocket ds = new DatagramSocket(10086);
        ds.receive(dp);
        // 解析数据 (拆包裹)
        byte[] bytes = dp.getData();
        int len = dp.getLength();
        String mess = new String(bytes,0,len);
        System.out.println(dp.getAddress().getHostAddress()+"--"+mess);

    }
}

使用循环优化

客户端

package s0807;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;

public class Send {
    public static void main(String[] args) throws Exception {
        // 填写 收件人信息
        InetAddress ia = InetAddress.getByName("localhost");
        Scanner input = new Scanner(System.in);
        while(true){
            // 包裹内容
            System.out.print("请输入: ");
            String mess = input.nextLine();
            byte[] bys = mess.getBytes();
            // 1- 封装一个包裹
            /**
             * 四个参数
             */
            DatagramPacket dp = new DatagramPacket(bys,bys.length,ia,10086);
            //  发送包裹
            DatagramSocket ds = new DatagramSocket();
            ds.send(dp);
            // 关闭资源包
            ds.close();
        }
    }
}

服务器端

package s0807;

import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class Receive {
    public static void main(String[] args) throws Exception {
        // 新建包裹 用于接收内容
        byte bys[] = new byte[1024];
        DatagramPacket dp = new DatagramPacket(bys,1024);

        // 新建监听包裹的套接字
        DatagramSocket ds = new DatagramSocket(10086);
        while(true){
            ds.receive(dp);
            // 解析数据 (拆包裹)
            byte[] bytes = dp.getData();
            int len = dp.getLength();
            String mess = new String(bytes,0,len);
            System.out.println(dp.getAddress().getHostAddress()+"--"+mess);
        }
    }
}

使用线程, 既能接收又能发送

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值