java网络编程基础

网络编程

1.网络编程的目的
  • 实现资源的共享
  • 实现数据的传输和下载
1.1软件的架构

网络的通信都是基于软件结构实现的:C/S结构 和 B/S结构

  • C/S架构 全称为Client /Server 架构,就是客服端和服务器端

    • 常见的程序像QQ、迅雷、IDEA等软件
    • 优点 :客户体验好,因为客户需要把客服端下载下来
    • 缺点:需要下载 后期需要维护比较麻烦
  • B/S架构 全称为Browser/Server 架构 ,就是浏览器和服务器架构

    • 常见的浏览器:谷歌、火狐等
    • 常见的软件:博学谷、京东、淘宝
    • 优点 :方便 在网页上就可以直接浏览这些服务器,不需要下载
    • 缺点: 网络不好 客户体验效果极差
1.2网络通信的三要素

网通通信必须要有一定约定,不然无法实现计算机之间的通信

  1. 协议:

    • 计算机网络客户端与服务端通信必须事先约定和彼此遵守的通信规则
    • HTTP , FTP , TCP , UDP , SSH , SMTP
  2. IP地址:

    • ip地址全称(Internet Protocol Address)互联网协议地址
    • IP 地址分为两种
      • IPv4:4个字节,32位组成 192.168.70.70 每一位取值0-225
      • IPv6: 可以实现为所有设备分配IP 128位
    • 本地的IP地址:127.0.0.1或者localhost

注意:只获得IP地址的话,能连接到那个计算机,并不能链接到具体的应用

3.端口号:

  • 端口号就用来唯一标识设备中的进程也就是应用程序
  • 用两个字节表示的整数,它的取值范围是0~65535
    • 0~1023之间的端口号用于一些知名的网络服务和应用
    • 普通的应用程序需要使用1024以上的端口号

总结:利用这三要素,就可以实现网络的通信

1.3网络通信的分层和协议
-------------------------------------------------------------------------------
应用层  :应用程序(QQ,微信,浏览器),可能用到的协议(HTTP,FTP,SMTP)通常程序员只需要关心这一层
------------------------------------------------------------------------------
传输层  :TCP/IP协议 - UDP协议    计算机网络工程师需要精通的协议
-----------------------------------------------------------------
网络层  :IP协议  封装自己的IP和对方的IP和端口
-----------------------------------------------------------------
数据链路层 : 进入到硬件(网)
-----------------------------------------------------------------
1.4 InetAddress类

在java中我们用InetAddress类来代表IP地址的对象,

这个类不能创建实例,通过静态方法返回IP地址对象。

InetAddress类成员方法:

  • static InetAddress getLocalHost() 获得本地主机IP地址对象
  • static InetAddress getByName(String host) 根据IP地址字符串或主机名获得对应的IP地址对象
  • String getHostName() 获得主机名
  • String getHostAddress() 获得IP地址字符串

测试代码

package com.net;

import java.io.IOException;
import java.net.InetAddress;

public class InetAddressDemo01 {
    public static void main(String[] args) throws IOException {
        //获取IP地址对象
        InetAddress localHost = InetAddress.getLocalHost();
        System.out.println(localHost.getHostAddress());// 获取ip地址
        System.out.println(localHost.getHostName()); //获取主机名

       //用域名获取域名ip对象
        InetAddress ip2 = InetAddress.getByName("www.baidu.com");
        System.out.println(ip2.getHostAddress());
        System.out.println(ip2.getHostName());

        // 判断是否能通: ping  3s之前测试是否可通
        System.out.println(ip2.isReachable(3000)); // ping
    }
}

运行结果:

在这里插入图片描述

1.5 UDP通信的使用介绍

1.UDP协议的特点:

  • 面向无连接的协议
  • 发送端只管发送,不确认对方是否能收到
  • 基于数据包进行数据传输
  • 发送数据的包的大小限制64KB以内
  • 因为面向无连接,速度快,但是不可靠,会丢失数据!

2.UDP协议相关的两个类:

DatagramPacket类构造器的详细解析:

  1. 根据构造器参数的不同,它分为发送端构造器,和接收端使用的构造器
    1.1发送端用的构造器:
    new DatagramPacket(byte[] buf, int length, InetAddress address, int port) 用来创建发送端对象
    buf:要发送的内容,字节数组
    length:要发送内容的长度,单位是字节
    address:接收端的IP地址对象
    port:接收端的端口号

    1.2接受端用的构造器:
    new DatagramPacket(byte[] buf, int length) 创建接收端的数据包对象
    buf:用来存储接收到内容
    length:能够接收内容的长度

  2. 实现思路:

      1. 创建一个DatagramPacket(数据包对象)对象用来封装要发送的数据,他只是存储封装数据,发送数据要用DatagramSocket类
      2. 创建一个服务端接收的类,接收客服端发送的数据
    
package com.net;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UDPClientDemo01 {
    public static void main(String[] args) throws IOException {
        System.out.println("客服端启动");
        byte[] bytes = "你好,吃了没".getBytes();//要发送的内容
        DatagramPacket packet = new DatagramPacket(bytes, bytes.length, InetAddress.getLocalHost(), 9966);
        DatagramSocket socket = new DatagramSocket();
        socket.send(packet); //发送packet对象
        socket.close();//关闭资源
    }
}
package com.net;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class UDPServerDemo02 {
    public static void main(String[] args) {
        System.out.println("服务器端启动");
        byte[] bytes = new byte[1024*64]; //创建一个接收客户都端的数据包对象
        DatagramPacket packet = new DatagramPacket(bytes,bytes.length);
        //创建一个接收端的对象
        DatagramSocket socket;
            try {
                socket = new DatagramSocket(9966);//这个端口号要和发送端的一致
                //开始接收
                socket.receive(packet);
                int len = packet.getLength();//获取接收的长度
                String str = new String(bytes,0,len);
                System.out.println(str);
                System.out.println("服务器端已收到");

                //服务端还可以获取发来信息的客户端的IP和端口
                String ip = packet.getAddress().getHostAddress();
                int port = packet.getPort();
                System.out.println("发送端的ip地址"+ip+"\n"+"对方的端口号是:"+port);
                socket.close();
            } catch (SocketException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
    }
}

行结果:

在这里插入图片描述
在这里插入图片描述

1.6 TCP通信协议详解:
  1. TCP/IP协议是安全可靠的传输协议,只有连接服务器成功之后,才会发送数据,

多用于文件上传和下载, 邮件发送和接收,远程登录,因为我们要确保不丢失数据

  1. TCP/IP协议的特点:
  • 面向连接的协议
  • 只能由客户端主动发送数据给服务器端,服务器端接收到数据之后,可以给客户端响应数据
  • 通过三次握手建立连接,连接成功形成数据传输通道
  • 通过四次挥手断开连接
  • 基于IO流进行数据传输
  • 传输数据大小没有限制
  • 因为面向连接的协议,速度慢,但是是可靠的协议
  1. Java中TCP相关的类:Socket and ServerSoket

    Socket 类的构造方法:

  • Socket(String host, int port) 传入IP地址和端口号

  • 注意事项:只要执行该方法,就会立即连接指定的服务器程序,如果连接不成功,则会抛出异常,如果连接成功,则表示三次握手通过。

    Socket类常用方法:

  • OutputStream getOutputStream(); 获得字节输出流对象

  • InputStream getInputStream(); 获得字节输入流对象

ServerSoket代表服务器对象:

  • public ServerSocket(int port) 获取客服端的端口号

  • public Socket accept() 接收客服端的连接请求 ,成功连接返回Socket对象

    代码实现:

    package com.net;
    
    import java.io.IOException;
    import java.io.OutputStream;
    import java.io.PrintStream;
    import java.net.Socket;
    
    public class ClientDemo01 {
        public static void main(String[] args) throws IOException {
            //1.创建客服端的对象
            Socket socket = new Socket("LocalHost", 9966);
            //2.获取从socket管道中获得字节输出流
            OutputStream outputStream = socket.getOutputStream();
            //3.把低级流转换成高级输出流
            PrintStream ps = new PrintStream(outputStream);
            //发送消息
            ps.println("你好服务器,我是客服端");
            ps.flush();//刷新
            System.out.println("客服端发送数据完毕~");
        }
    }
    
    package com.net;
    
    import java.io.*;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class ServerDemo01 {
        public static void main(String[] args) throws IOException {
            System.out.println("服务端开始启用");
            //1.创建服务器端的对象
            ServerSocket serverSocket = new ServerSocket(9966);
            //2.开始等待接收客服端的socket连接
            Socket acceptSocket = serverSocket.accept();
            //3.连接成功,获取socket的字节输入流
            InputStream inputStream = acceptSocket.getInputStream();
            //4.把字节输入流转为字符输入流
            Reader reader = new  InputStreamReader(inputStream);
            //5..把字符输入流包装成缓冲字符输入流
            BufferedReader br = new BufferedReader(reader);
            //6.按照一行一行的读  以为发送的是一行一行发送的
            String line;
            if((line = br.readLine())!=null){
                System.out.println(line);
            }
        }
    }
    

在这里插入图片描述
在这里插入图片描述

改进客服端手动发数据

package com.net;

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

public class ClientDemo01 {
    public static void main(String[] args) throws IOException {
        //1.创建客服端的对象
        Socket socket = new Socket("LocalHost", 9966);
        //2.获取从socket管道中获得字节输出流
        OutputStream outputStream = socket.getOutputStream();
        //3.把低级流转换成高级输出流
        PrintStream ps = new PrintStream(outputStream);
        //一直发发送消息
        while (true){
            Scanner scanner = new Scanner(System.in);
            System.out.print("客服端:");
            ps.println(scanner.nextLine());//一行一行的写
            ps.flush();
        }
    }
}
package com.net;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerDemo01 {
    public static void main(String[] args) throws IOException {
        System.out.println("服务端开始启用");
        //1.创建服务器端的对象
        ServerSocket serverSocket = new ServerSocket(9966);
        //2.开始等待接收客服端的socket连接
        Socket acceptSocket = serverSocket.accept();
        //3.连接成功,获取socket的字节输入流
        InputStream inputStream = acceptSocket.getInputStream();
        //4.把字节输入流转为字符输入流
        Reader reader = new  InputStreamReader(inputStream);
        //5..把字符输入流包装成缓冲字符输入流
        BufferedReader br = new BufferedReader(reader);
        //6.一直读
        String line;
        while ((line = br.readLine())!= null){
            System.out.println(line);
        }
    }
}

在这里插入图片描述
在这里插入图片描述

多线程 实现多个客服端发送数据

package com.net;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
public class ClientDemo01 {
    public static void main(String[] args) throws IOException {
        //1.创建客服端的对象
        Socket socket = new Socket("LocalHost", 9966);
        //2.获取从socket管道中获得字节输出流
        OutputStream outputStream = socket.getOutputStream();
        //3.把低级流转换成高级输出流
        PrintStream ps = new PrintStream(outputStream);
        //一直发发送消息
        while (true){
            Scanner scanner = new Scanner(System.in);
            System.out.print("客服端:");
            ps.println(scanner.nextLine());//一行一行的写
            ps.flush();
        }
    }
}

package com.net;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerDemo02 {
    public static void main(String[] args) throws IOException {
        System.out.println("服务器端启用");
        //1.获取服务器端对象
        ServerSocket serverSocket = new ServerSocket(9966);
        //2.循环来接收不同线程的客服端对象
        while(true){
            Socket acceptSocket = serverSocket.accept();
            Thread thread = new ServerReaderThread(acceptSocket);
            thread.start();
        }
    }
}
class ServerReaderThread extends Thread{
    Socket socket;
    public ServerReaderThread(Socket acceptSocket) {
        this.socket = acceptSocket;
    }
    @Override
    public void run() {
        try {
            //3.获取socket管道的字节输入流
            InputStream inputStream = socket.getInputStream();
            //4.包装成缓冲流
            BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
            //5.读取数据
            String line ;
            while ((line = br.readLine())!=null){
                System.out.print(socket.getRemoteSocketAddress());//获取当前线程的IP地址
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println(socket.getRemoteSocketAddress()+"下线线了~");
        }
    }
}

运行图:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值