• Java 网络编程(大全)


    前言必读

    读者手册(必读)_云边的快乐猫的博客-CSDN博客

    一、1网络通信的基本模式分为两种

    1.CS模式(Client---客户端,Server---服务端) 

    客户端是需要程序员去开发的,例如日常使用的各种的APP,服务端就是服务器。

    例子:端游,依赖特定的PC端才能玩。

    2.BS模式(Browser---浏览器,Server---服务端)---重点学习

    服务端是需要程序员去开发的。浏览器就是我们日常使用的浏览器去访问各种网站,只要有浏览器就可以访问,不依赖特定的PC端,在任意设备上都可以访问网站服务器 。

    例子:网页小游戏,联网浏览器就可以玩。 

    一、2 请分析C/S和B/S架构相比的各自的优缺点?

    1.CS(客户端--服务器结构)

    优点 技术成熟,交互性强,网络通信量低,响应数据快。将任务分到了两端,降低了系统的开销。客户端要处理大多数的业务逻辑和UI展示。他是胖客户端。

    缺点:更新太快,要求用户有相同的操作系统,如果有不同的操作系统还要开发不同的版本,对于计算机电脑的配置要求也高

    2。BS(浏览器-服务器结构)

    优点:主要事务在服务端实现。分布性强、维护方便、开发简单

    共享性强、总体成本低,对客户端的电脑配置要求较低

    缺点:数据安全性问题,对服务器要求高。数据传输速度较慢,软件的个性化明显降低,难以实现传统模式下的特殊功能要求,他是瘦客户端,大量的数据的传输都要通过服务器与浏览器进行交互,通信开销大,难以实现复杂的应用构造

    二、实现网络编程的三种要素

    IP地址可以理解为具体哪个计算机,端口理解计算机上的程序(一个程序一个端口),协议理解为电脑通过什么方式和外界交互

    要素一:IP地址:设备在网络中的地址,是唯一的标识

    详解:

    (1)常见的IP分类为:

    IPv4(32比特4字节)和IPv6(128位16个字节)--称号--可以标记地球上的每一粒沙子。

    (2)IP地址的取经之路:

    计算机:我要去找百度获取数据。

    DNS服务器:发过来我看看哪个网址域名啊,给你指路具体的ip地址

    计算机:知道了这个ip地址,我就可以去找具体要访问的服务器了

    服务器:计算机老弟你来找我了啊,那我把你要的数据发给你吧。 

    (3)公网地址和私有地址(局域网使用)

    192.168开头的就是常见的私有地址 

    (4)获取IP地址的代码

     要去实现这个IP地址的获取就要用到 InetAddress方法

    代码例子:

    1. package bao;
    2. import java.net.InetAddress;
    3. public class Test {
    4. public static void main(String[] args) throws Exception {
    5. //1.获取本机地址ip对象
    6. InetAddress ip1 = InetAddress.getLocalHost();
    7. System.out.println(ip1.getHostName());//获取主机名字
    8. System.out.println(ip1.getHostAddress());//获取ip地址
    9. //2.获取域名ip对象
    10. InetAddress ip2 = InetAddress.getByName("www.baidu.com");
    11. System.out.println(ip2.getHostName());//获取域名
    12. System.out.println(ip2.getHostAddress());//获取域名的ip地址
    13. //3.获取公网对象
    14. InetAddress ip3 = InetAddress.getByName("112.80.248.76");
    15. System.out.println(ip3.getHostName());//获取公网名字
    16. System.out.println(ip3.getHostAddress());//获取公网ip地址
    17. //判断网络是否能连接通信 ping 5s之前测试是否能通过
    18. System.out.println(ip3.isReachable(5000));//通过会返回true
    19. }
    20. }

    运行结果:

    涉及到个人隐私就不放到这里来了,可以自己运行试试看  

     =========================================================================

    要素二:端口:应用程序在设备中的唯一标识

    一个主机设备中,端口号是唯一的

    (1)端口号:一个程序一个端口号,被规定为16位的二进制,范围是0~65535

    (2)周知端口:0~1023,被预先定义的知名应用占用。(例如:HTTP占用80端口,FTP占用21端口)

    (3)注册端口:1024~49151,分配给用户进程或某些程序(例如:Tomcat占用8080端口)

    (4)动态端口:49152~65535,不固定分配到某种进程,动态分配

     =========================================================================

    要素三:协议:数据在网络中的传输协议,最常见的有UDP和TCP(重点)

    (1)TCP协议: (安全,有连接确认可靠)

    使用TCP协议,双方必须先建立连接,它是一种面向连接可靠通信协议,传输前,要建立三次握手方式建立连接确认。连接和发送数据都需要确认。传输完成后,还需要释放已连接的通信,通信效率相对比较低。

    使用场景:对安全需求较高的文件下载、金融数据通信等。

    三次握手连接:

    客户端:在吗?

    服务端:在

    客户端:上号

    四次握手断开连接:

    客户端:不玩了

    服务端:好吧

    服务端:下次什么时候玩?

    客户端:有空再玩 

    例子:

    一收一发

    发送端(客户端) 

    1. package bao;
    2. import java.io.IOException;
    3. import java.io.OutputStream;
    4. import java.io.PrintStream;
    5. import java.net.Socket;
    6. //发送端
    7. public class Test {
    8. public static void main(String[] args) throws IOException {
    9. System.out.println("==============客户端启动===============");
    10. //1.创建发送通信管道
    11. Socket socket = new Socket("127.0.0.1",7777);//参数一:服务端地址 参数二:服务端端口
    12. //2.从scoket管道中获得一个字节输出流,负责发送数据
    13. OutputStream os = socket.getOutputStream();
    14. //3.字节流升级成打印流
    15. PrintStream ps = new PrintStream(os);
    16. //4.发送消息
    17. ps.println("大哥,我来了");
    18. ps.flush();//刷新
    19. }
    20. }

     接收端 (服务端)

    1. package bao;
    2. import java.io.BufferedReader;
    3. import java.io.IOException;
    4. import java.io.InputStream;
    5. import java.io.InputStreamReader;
    6. import java.net.ServerSocket;
    7. import java.net.Socket;
    8. //服务端
    9. public class Test1 {
    10. public static void main(String[] args) throws IOException {
    11. System.out.println("========服务端启动============");
    12. //1.创建接收管道,注册端口
    13. ServerSocket serverSocket = new ServerSocket(7777);//参数一:定义服务端口
    14. //2.等待管道连接
    15. Socket accept = serverSocket.accept();
    16. //3.从管道中获取一个字节输入流
    17. InputStream is = accept.getInputStream();
    18. //4.字节流升级生缓冲输入流
    19. BufferedReader br = new BufferedReader(new InputStreamReader(is));
    20. //5.按照行读取消息会更好
    21. String a;
    22. if ((a = br.readLine())!=null){
    23. System.out.println(accept.getRemoteSocketAddress()+"说了:"+a);
    24. }
    25. }
    26. }

     运行结果:

    /127.0.0.1:60316说了:大哥,我来了

     ==============客户端启动===============

    多收多发 

    发送端(客户端) 

    1. package bao;
    2. import java.io.*;
    3. import java.net.InetAddress;
    4. import java.net.Socket;
    5. import java.util.Scanner;
    6. public class kehu {
    7. public static void main(String[] args) throws Exception {
    8. System.out.println("客户端启动");
    9. //1.创建与服务端连接的管道
    10. Socket s = new Socket(InetAddress.getLocalHost(), 9966);
    11. //2.创建一个线程负责客户端的消息读取
    12. new ClientReaderThread(s).start();
    13. //3.创建一个字节输入流管道
    14. OutputStream o = s.getOutputStream();
    15. PrintStream p = new PrintStream(o);//升级流
    16. //4.客户端输入数据
    17. Scanner sc = new Scanner(System.in);
    18. while (true){
    19. System.out.println("请输入:");
    20. String s1 = sc.nextLine();
    21. p.println(s1);//发送数据出去
    22. p.flush();//刷新流
    23. }
    24. }
    25. }
    26. class ClientReaderThread extends Thread{
    27. private Socket socket;
    28. public ClientReaderThread(Socket socket){
    29. this.socket = socket;
    30. }
    31. @Override
    32. public void run(){
    33. try {
    34. //把字节输入流包装成字符输入流
    35. InputStream i = socket.getInputStream();
    36. BufferedReader b = new BufferedReader(new InputStreamReader(i));
    37. String s1;
    38. while (true){
    39. if ((s1=b.readLine())!=null){
    40. System.out.println("收到了消息"+s1);
    41. }
    42. }
    43. } catch (IOException e) {
    44. System.out.println("服务器把你提出群聊");
    45. }
    46. }
    47. }

      接收端 (服务端)

    1. package bao;
    2. import java.io.*;
    3. import java.net.ServerSocket;
    4. import java.net.Socket;
    5. import java.util.ArrayList;
    6. import java.util.List;
    7. public class fuwu {
    8. //1.定义一个静态变量储存全部管道
    9. public static List all_Sockets = new ArrayList<>();
    10. public static void main(String[] args) throws IOException {
    11. System.out.println("服务端启动成功");
    12. //2.服务端口注册
    13. ServerSocket ss = new ServerSocket(9966);
    14. //3.管道死循环设置
    15. while (true){
    16. Socket s = ss.accept();
    17. System.out.println(s.getRemoteSocketAddress()+"上线了");
    18. all_Sockets.add(s);
    19. new fuwuThread(s).start();
    20. }
    21. }
    22. }
    23. class fuwuThread extends Thread{
    24. private Socket socket;
    25. public fuwuThread(Socket socket){
    26. this.socket=socket;
    27. }
    28. @Override
    29. public void run(){
    30. try {
    31. InputStream i = socket.getInputStream();
    32. BufferedReader b = new BufferedReader(new InputStreamReader(i));
    33. String s1;
    34. while ((s1=b.readLine())!=null){
    35. System.out.println(socket.getRemoteSocketAddress()+"说"+s1);
    36. sendMessage(s1);
    37. }
    38. } catch (IOException e) {
    39. System.out.println(socket.getRemoteSocketAddress()+"离线了");
    40. fuwu.all_Sockets.remove(socket);
    41. }
    42. }
    43. private void sendMessage (String s1) throws IOException {
    44. for (Socket s:fuwu.all_Sockets){
    45. OutputStream o = s.getOutputStream();
    46. PrintStream p = new PrintStream(o);
    47. p.println(s1);
    48. p.flush();
    49. }
    50. }
    51. }

    运行结果:

    服务端启动成功
    /192.168.78.1:56384上线了
    /192.168.78.1:56384说大哥
    /192.168.78.1:56389上线了
    /192.168.78.1:56389说小弟
    /192.168.78.1:56384说
    /192.168.78.1:56384说大哥11

    客户端启动
    请输入:
    大哥
    请输入:
    收到了消息大哥
    收到了消息小弟

    大哥11
    请输入:
    请输入:
    收到了消息
    收到了消息大哥11

    客户端启动
    请输入:
    小弟
    请输入:
    收到了消息小弟
    收到了消息
    收到了消息大哥11 

     =========================================================================

                                                                TCP和UDP的分界线

     =========================================================================

    (2)UDP协议:(速度快,无连接,不可靠)

    不需要建立连接(因为把数据源IP、目的地IP、端口封装成数据包),每个数据包在64KB内,只管发,不管对方有没有接到确认什么的。

    优点:可以广播发送,发送数据结束时无需释放资源,开销小,速度快。

    使用场景:语言通话、视频通话等。

    ps:这个就是一股脑的什么都封装一起,直接往外抛就什么都不管了,当然快了。

    例子:

    一收一发

    发送端(客户端)

    1. package bao;
    2. import java.net.DatagramPacket;
    3. import java.net.DatagramSocket;
    4. import java.net.InetAddress;
    5. public class Test {
    6. public static void main(String[] args) throws Exception {
    7. //一、发送端(测试时候先启动接收再发送端)
    8. //1.创建发送端对象,发送端自带默认端口号(人)
    9. System.out.println("========客户端启动============");
    10. DatagramSocket socket1 = new DatagramSocket();//不定义就默认端口
    11. //2.创建一个要发送的数据容器(容器里面有数据)
    12. byte[] a ="我是水".getBytes();
    13. //3.创建一个数据包对象把容器装起来
    14. DatagramPacket packet1 = new DatagramPacket(a,a.length, InetAddress.getLocalHost(),8899);//数据,大小,服务端的IP,服务端的端口
    15. //4.发送出去
    16. socket1.send(packet1);
    17. //5.关闭资源,避免资源浪费
    18. socket1.close();
    19. }
    20. }

    接收端 (服务端)

    1. package bao;
    2. import java.net.DatagramPacket;
    3. import java.net.DatagramSocket;
    4. public class Test1 {
    5. public static void main(String[] args) throws Exception {
    6. //二、接收端(测试时候先启动接收再发送端)
    7. //1.创建接收端对象,注册端口(人)
    8. System.out.println("=========接收端启动===============");
    9. DatagramSocket socket2 = new DatagramSocket(8899);
    10. //2.创建一个要接收的数据容器(等待接收数据)
    11. byte[]b =new byte[1024*64];
    12. //3.把容器数据打包
    13. DatagramPacket packet2 = new DatagramPacket(b,b.length);
    14. //4.等待接收数据
    15. socket2.receive(packet2);
    16. //5.读取多少倒出多少
    17. int len = packet2.getLength();
    18. String rs = new String(b,0,len);
    19. System.out.println("接收到了数据了"+rs);
    20. //6.关闭资源,避免资源浪费
    21. socket2.close();
    22. }
    23. }
    24. //额外知识点,获取对方端口和ip地址
    25. //String ip = packet2.getAddress().toString();
    26. //System.out.println("对方IP地址为"+ip);
    27. //int port = packet2.getPort();
    28. //System.out.println("对方端口位置"+port);

    运行结果:

    ========客户端启动============ 

    =========接收端启动===============
    接收到了数据了我是水 

    多收多发

    思想:把一收一发代码拿来改进就好了

    发送端:把主要发送的代码写入死循环并写一个键盘输入代码,只有用户输入exit才能退出循环。

    接收端:把等待接收的封装包开始写入死循环里面,然后再把释放资源的代码注释掉才能一直接收

    发送端(客户端)

    1. package bao;
    2. import java.net.DatagramPacket;
    3. import java.net.DatagramSocket;
    4. import java.net.InetAddress;
    5. import java.util.Scanner;
    6. //发送端
    7. public class Test {
    8. public static void main(String[] args) throws Exception {
    9. //一、1.创建发送端对象,发送端自带默认端口号(人)
    10. DatagramSocket socket1 = new DatagramSocket();//不定义就默认端口
    11. System.out.println("========客户端启动============");
    12. //二.6创建键盘录入
    13. Scanner sc = new Scanner(System.in);
    14. while (true) {//二、5.死循环把代码封起来(多收多发步骤)
    15. //二、6.接收键盘录入
    16. System.out.println("请输入:");
    17. String msg = sc.nextLine();
    18. //二、7.设置exit退出
    19. if ("exit".equals(msg)){
    20. System.out.println("离线成功");
    21. socket1.close();//释放资源
    22. break;
    23. }
    24. //2.创建一个要发送的数据容器(容器里面有数据)
    25. byte[] a =msg.getBytes();
    26. //3.创建一个数据包对象把容器装起来
    27. DatagramPacket packet1 = new DatagramPacket(a,a.length, InetAddress.getLocalHost(),8899);//数据,大小,服务端的IP,服务端的端口
    28. //4.发送出去
    29. socket1.send(packet1);
    30. }
    31. }
    32. }

    接收端 (服务端)

    1. package bao;
    2. import java.net.DatagramPacket;
    3. import java.net.DatagramSocket;
    4. //二、接收端
    5. public class Test1 {
    6. public static void main(String[] args) throws Exception {
    7. //1.创建接收端对象,注册端口(人)
    8. System.out.println("=========接收端启动===============");
    9. DatagramSocket socket2 = new DatagramSocket(8899);
    10. //2.创建一个要接收的数据容器(等待接收数据)
    11. byte[]b =new byte[1024*64];
    12. //3.把容器数据打包
    13. DatagramPacket packet2 = new DatagramPacket(b,b.length);
    14. while (true) {//二、6.把封装代码写入死循环并删掉释放资源的代码(多收多发步骤)
    15. //4.等待接收数据
    16. socket2.receive(packet2);
    17. //5.读取多少倒出多少
    18. int len = packet2.getLength();
    19. String rs = new String(b,0,len);
    20. System.out.println("接收到了来自:"+packet2.getAddress()+"对方端口是:"+packet2.getPort()+rs);
    21. }
    22. }
    23. }
    24. //额外知识点,获取对方端口和ip地址
    25. //String ip = packet2.getAddress().toString();
    26. //System.out.println("对方IP地址为"+ip);
    27. //int port = packet2.getPort();
    28. //System.out.println("对方端口位置"+port);

    运行结果: 

    ========客户端启动============
    请输入:
    你在吗
    请输入:
    在干嘛
    请输入: 

    =========接收端启动===============
    接收到了来自:(隐私不展示)对方端口是:(隐私不展示)你在吗
    接收到了来自:(隐私不展示)对方端口是:(隐私不展示)在干嘛

    多开客户端 步骤

    一台主机中可以创建很多个客户端给接收端发消息 

     1.在客户端的页面右上角点击

    2.找到Allow multiple instances勾选完成

     广播(当前主机和所在网络中的所有主机通信)

    步骤:(前提在同一网段内)

    发送端的参数地址指定为255.255.255.255,并且指定端口:例如6666

    接收端的参数端口只要匹配成功就可以了,例如:6666

    例子:

    发送端

    1. //修改前
    2. //3.创建一个数据包对象把容器装起来
    3. DatagramPacket packet1 = new DatagramPacket(a,a.length, InetAddress.getLocalHost(),8899);//数据,大小,服务端的IP,服务端的端口
    4. //修改后
    5. //3.创建一个数据包对象把容器装起来
    6. DatagramPacket packet1 = new DatagramPacket(a,a.length, InetAddress.getByName("255.255.255.255"),6666);//数据,大小,服务端的IP,服务端的端口

     接收端

    1. //修改前
    2. //1.创建接收端对象,注册端口(人)
    3. System.out.println("=========接收端启动===============");
    4. DatagramSocket socket2 = new DatagramSocket(8899);
    5. //修改后
    6. //1.创建接收端对象,注册端口(人)
    7. System.out.println("=========接收端启动===============");
    8. DatagramSocket socket2 = new DatagramSocket(6666);

    组播 (当前主机和所在网络中的一组主机通信)

    发送端和接收端都要用MulticastSocket绑定同一个IP地址和绑定同一个端口

    范围:224.0.0.0~~~~239.255.255.255

    发送端

    1. //修改前
    2. //3.创建一个数据包对象把容器装起来
    3. DatagramPacket packet1 = new DatagramPacket(a,a.length, InetAddress.getByName("255.255.255.255"),6666);//数据,大小,服务端的IP,服务端的端口
    4. //修改后
    5. //3.创建一个数据包对象把容器装起来
    6. DatagramPacket packet1 = new DatagramPacket(a,a.length, InetAddress.getByName("224.0.1.1"),6666);//数据,大小,服务端的IP,服务端的端口

    接收端

    1. //修改前
    2. //1.创建接收端对象,注册端口(人)
    3. System.out.println("=========接收端启动===============");
    4. DatagramSocket socket2 = new DatagramSocket(6666);
    5. //修改后
    6. //1.创建接收端对象,注册端口(人)
    7. System.out.println("=========接收端启动===============");
    8. MulticastSocket socket2 = new MulticastSocket(6666);
    9. //绑定组播IP(JDK开始过时的API)
    10. socket2.joinGroup(InetAddress.getByName("224.0.1.1"));
  • 相关阅读:
    使用grpcui测试ASP.NET core gRPC服务
    C++ 内联函数的作用
    外卖市场繁荣背后,外卖员保障缺失的困境与突围
    数据库管理系统:Redis配置与使用
    服务器数据恢复-linux+raid+VMwave ESX数据恢复案例
    Java核心技术卷Ⅰ-第一章Java程序设计概述
    【腾讯云 Cloud Studio 实战训练营】使用python爬虫和数据可视化对比“泸州老窖和五粮液4年内股票变化”
    经典C语言题目程序题(函数篇)
    Nginx 访问http强制自动跳转到https
    2022第十一届PMO大会(线上会议)成功召开
  • 原文地址:https://blog.csdn.net/m0_52861000/article/details/126901321