Java 网络编程

网络编程

一、了解网络

网络的概念

  • 网络:一组相互连接的计算机
    1、多台计算机组成。
    2、使用物理线路进行连接。

二、网络编程的三要素

  1. IP地址:唯一标识网络上的每台计算机;是两台计算机之间通信的必备要素。
  2. 端口号:计算机中应用的标号:代表一个应用程序);0-1024系统使用或保留端口,有效端口0-65536.
  3. 通信协议:通信的规则,包含TCP和UDP。
  1. 网络中的每台计算机都有一个唯一的IP地址,网络通过IP地址进行通信。
  2. 计算机A使用QQ与外界交流,那么计算机B的使用者只能通过QQ去解析对方发来的信息,计算机中有那么多的应用程序,使用数字来对这些网络应用程序做标识,这些数字形象的称之为端口号。
  3. 通信之间必须使用相同的规则,这些规则叫协议,国际通用协议TCP/UDP。

网络模型

OSI参考模型

开放系统互连参考模型(Open System Interconnect)

TCP/IP参考模型

传输控制/国际协议(Transfer Controln Protocol/Internet Protocol)

IP地址

IP地址的表示方法

IP地址:32位,由4个8位二进制数组成。

IP表示方法:点分十进制。

IP地址=网络ID+主机ID

  • 网络ID:标识计算机或网络设备所在的网段。
  • 主机ID:标识特定主机或网络设备。

IP地址的分类

地址类用于指定网络ID并在网络ID和主机ID之间提供分隔方法。

IANA负责分配A、B、C类网络地址,具体主机地址由机构组织自行分配。
IP地址类分类:

  1. A类:一个A类IP地址由1字节的网络地址和3字节主机地址组成,它主要为大型网络而设计的,网络地址的最高位必须是"0", 地址范围从1.0.0.0 到127.0.0.0)。可用的A类网络有127个,每个网络能容纳16777214个主机。
  2. B类:一个B类IP地址由2个字节的网络地址和2个字节的主机地址组成,网络地址的最高位必须是"10",地址范围从128.0.0.0到191.255.255.255。可用的B类网络有16382个,每个网络能容纳6万多个主机 。
  3. C类:一个C类IP地址由3字节的网络地址和1字节的主机地址组成,网络地址的最高位必须是"110"。范围从192.0.0.0到223.255.255.255。C类网络可达209万余个,每个网络能容纳254个主机。
  4. D类: D类IP地址是一个专门保留的地址。它并不指向特定的网络,目前这一类地址被用在多点广播(Multicast)中。多点广播地址用来一次寻址一组计算机,它标识共享同一协议的一组计算机。224.0.0.0到239.255.255.255用于多点广播 。
  5. E类:以"llll0"开始,为将来使用保留。240.0.0.0到255.255.255.254,255.255.255.255用于广播地址。

注:在IP地址3种主要类型里,各保留了3个区域作为私有地址,其地址范围如下:

A类地址:10.0.0.0~10.255.255.255

B类地址:172.16.0.0~172.31.255.255

C类地址:192.168.0.0~192.168.255.255

特殊的IP地址

0.0.0.0:本机。

127.0.0.1:本机回环地址,用于本机测试。

255.255.255.255:当前子网,一般用于向当前子网广播信息。

IP地址所对应的对象(InetAddress)

方法 描述
public static InetAddress getLocalhost( ) 获取主机名和IP地址
public String getHostAddress( ) 获取IP地址
public String getHostName( ) 获取主机名
public static InetAddress getByName(String host) 根据主机名获得IP地址

示例代码:

java 复制代码
public class InteAddressDemo {

    public static void main(String[] args) throws UnknownHostException {
        InetAddress localHost = InetAddress.getLocalHost();
        System.out.println(localHost);
        InetAddress inetAdd = InetAddress.getByName("www.baidu.com");
        System.out.println(inetAdd);
        System.out.println(inetAdd.getHostAddress());
        System.out.println(inetAdd.getHostName());
    }
}
/*  输出的结果是:
	// 此行会输出你的主机名和IP地址我就不漏出我的主机命和IP地址了
	www.baidu.com/183.2.172.42
	183.2.172.42
	www.baidu.com
*/

端口

端口:port

端口是虚拟的概念,并不是说在主机上真的有若干个端口。通过端口,可以在一个主机上运行多个网络应用程序。

传输协议

  • UDP:相当于发短信(有字数限制),不需要建立连接,数据报的大小在64k内,效率较高,但不安全,容易丢包。
  • TCP:相当于打电话,需要建立连接,效率相对比较低,数据传输安全,三次握手完成。(点名--》答到--》确认)

三、Socket套接字

  • 网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个Socket。
  • Java中使用Socket完成TCP程序的开发,使用此类可以方便的建立可靠的双向的持续性的点对点的通讯连接。
  • 在Socket的程序开发中,服务器端使用ServerSocket等待客户端的连接,对于Java的网络程序来讲,每个客户端都使用一个Socket对象表示。

基于TCP协议的Socket编程

进行网络通信时,Socket需要借助数据流来完成数据的传递工作。

演示案例: 互相传输一句话。

服务器端:

java 复制代码
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {

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

        //创建serverSocket对象
        ServerSocket serverSocket = new ServerSocket(10000);
        //获取服务端的套接字对象
        Socket socket = serverSocket.accept();
        //--------------------接收客户端的输入---------------
        //获取输入流对象
        InputStream inputStream = socket.getInputStream();
        byte[] buf = new byte[1024];
        int length = inputStream.read(buf);
        System.out.println("客户端传输的数据是:" + new String(buf,0,length));

        //------------------返回客户端数据------------------
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("你好,收到".getBytes());

        //关闭流操作
        outputStream.close();
        inputStream.close();
        socket.close();
        serverSocket.close();
    }
}
// 输出的结果是:
// 客户端传输的数据是:hello java

客户端:

java 复制代码
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class Client {

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

        //创建客户端的套接字
        Socket client = new Socket("127.0.0.1",10000);
        //------------------------向外进行输出------------------
        //获取输出流对象
        OutputStream outputStream = client.getOutputStream();
        //数据输出
        outputStream.write("hello java".getBytes());

        //------------------------接收服务端返回的消息-------------
        //获取输入流对象
        InputStream inputStream = client.getInputStream();
        byte[] buf = new byte[1024];
        int length = inputStream.read(buf);
        System.out.println("服务端的响应数据是:" + new String(buf,0,length));

        //关闭流操作
        inputStream.close();
        outputStream.close();
        client.close();
    }
}
// 输出的结果是:
// 服务端的响应数据是:你好,收到

演示案例: 客户端向服务器端提交一张照片。

服务器端:

java 复制代码
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class PicServer {

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

        //创建服务端对象,开放端口
        ServerSocket serverSocket = new ServerSocket(10086);
        //创建服务器的Socket
        Socket server = serverSocket.accept();
        //获取输入流对象
        InputStream inputStream = server.getInputStream();
        //创建文件输出流对象
        FileOutputStream fileOutputStream = new FileOutputStream("2.jpg");
        int temp = 0;
        while ((temp = inputStream.read()) != -1){
            fileOutputStream.write(temp);
        }
        //添加流输出完成的标志
        server.shutdownInput();
        //上传图片结束之后给予客户端响应
        OutputStream outputStream = server.getOutputStream();
        outputStream.write("上传成功".getBytes());
        server.shutdownOutput();

        //关闭流
        outputStream.close();
        fileOutputStream.close();
        inputStream.close();
        server.close();
        serverSocket.close();
    }
}

客户端:

java 复制代码
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class PicClient {

    public static void main(String[] args) throws Exception {

        //创建图片的输入流对象
        FileInputStream fileInputStream = new FileInputStream("1.jpg");
        //创建Socket
        Socket client = new Socket("localhost",10086);
        //获取输出流对象
        OutputStream outputStream = client.getOutputStream();
        int temp = 0;
        while ((temp = fileInputStream.read()) != -1){
            outputStream.write(temp);
        }
        client.shutdownOutput();
        //接收服务端的响应
        InputStream inputStream = client.getInputStream();
        byte[] buf = new byte[1024];
        int length = inputStream.read(buf);
        System.out.println(new String(buf,0,length));
        client.shutdownInput();

        //关闭流操作
        inputStream.close();
        outputStream.close();
        client.close();
        fileInputStream.close();
    }
}

注意: 要先启动服务器端再启动客户端。

Socket中实现对象的传递

如何传递对象信息呢?

java 复制代码
String info = "用户名:Lisi;用户密码:123456";
outputStream.write(info.getBytes());

序列化

java 复制代码
User user = new User();// User是用户类
user.setLoginName("Lisi");
user.setPassword("123456");
oos.writeObject(user);

演示案例: 实现用户登录。

  • 方法一
    用户类:
java 复制代码
import java.io.Serial;
import java.io.Serializable;

public class User implements Serializable {

    @Serial// 指定序列化版本号
    private static final long serialVersionUID = -8254223107980283532L;
    private String username;
    private String password;

    public User() {
    }

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

服务器端:

java 复制代码
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class LoginServer {

    public static void main(String[] args) throws Exception {

        ServerSocket serverSocket = new ServerSocket(10000);
        while (true){
            Socket server = serverSocket.accept();
            //获取输入流对象
            InputStream inputStream = server.getInputStream();
            //需要使用ObjectInputStream对象
            ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
            User user = (User) objectInputStream.readObject();
            String str = "";
            if ("lyf".equals(user.getUsername()) && "lyf".equals(user.getPassword())){
                str = "登录成功";
                System.out.println("欢迎您:" + user.getUsername());
            } else {
                str = "登录失败";
            }
            //截断输入流
            server.shutdownInput();
            //给客户端响应
            DataOutputStream dataOutputStream = new DataOutputStream(server.getOutputStream());
            dataOutputStream.writeUTF(str);
            server.shutdownOutput();

            //关闭流操作
            dataOutputStream.close();
            objectInputStream.close();
            inputStream.close();
            server.close();
        }
    }
}
// 输出的结果是:
// 欢迎您:lyf

客户端:

java 复制代码
import java.io.DataInputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class LoginClient {

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

        Socket client = new Socket("localhost",10000);
        OutputStream outputStream = client.getOutputStream();
        //完成用户登录功能,需要传输一个user对象
        User user = getUser();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
        objectOutputStream.writeObject(user);
        //调用shutdown方法告诉对方传输完成
        client.shutdownOutput();
        //接收响应
        DataInputStream dataInputStream = new DataInputStream(client.getInputStream());
        String str = dataInputStream.readUTF();
        System.out.println(str);

        //关闭流操作
        dataInputStream.close();
        objectOutputStream.close();
        outputStream.close();
        client.close();
    }

    public static User getUser(){
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String username = scanner.nextLine();
        System.out.println("请输入密码:");
        String password = scanner.nextLine();
        return new User(username,password);
    }
}
/*
请输入用户名:
lyf
请输入密码:
lyf
输入正确的用户名和密码后会返回:登录成功
*/
  • 方法二
    用户类:
java 复制代码
import java.io.Serial;
import java.io.Serializable;

public class User implements Serializable {

    @Serial// 指定序列化版本号
    private static final long serialVersionUID = -8254223107980283532L;
    private String username;
    private String password;

    public User() {
    }

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

服务器端:

java 复制代码
import java.net.ServerSocket;
import java.net.Socket;

public class LoginServer2 {

    public static void main(String[] args) throws Exception {

        ServerSocket serverSocket = new ServerSocket(10000);
        while (true){
            Socket socket = serverSocket.accept();
            LoginThread loginThread = new LoginThread(socket);
            new Thread(loginThread).start();
        }
    }
}
// 输出的结果是:
// 欢迎您:lyf

线程类:

java 复制代码
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;

public class LoginThread implements Runnable{

    private Socket socket;

    public LoginThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        ObjectInputStream objectInputStream = null;
        DataOutputStream dataOutputStream = null;
        try {
            objectInputStream = new ObjectInputStream(socket.getInputStream());
            User user = (User) objectInputStream.readObject();
            String str = "";
            if ("lyf".equals(user.getUsername()) && "lyf".equals(user.getPassword())){
                str = "登录成功";
                System.out.println("欢迎您:" + user.getUsername());
            } else {
                str = "登录失败";
            }
            socket.shutdownInput();
            dataOutputStream = new DataOutputStream(socket.getOutputStream());
            dataOutputStream.writeUTF(str);
            socket.shutdownOutput();

        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }finally {
            try {
                dataOutputStream.close();
                objectInputStream.close();
                socket.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

客户端:

java 复制代码
import java.io.DataInputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class LoginClient {

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

        Socket client = new Socket("localhost",10000);
        OutputStream outputStream = client.getOutputStream();
        //完成用户登录功能,需要传输一个user对象
        User user = getUser();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
        objectOutputStream.writeObject(user);
        //调用shutdown方法告诉对方传输完成
        client.shutdownOutput();
        //接收响应
        DataInputStream dataInputStream = new DataInputStream(client.getInputStream());
        String str = dataInputStream.readUTF();
        System.out.println(str);

        //关闭流操作
        dataInputStream.close();
        objectOutputStream.close();
        outputStream.close();
        client.close();
    }

    public static User getUser(){
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String username = scanner.nextLine();
        System.out.println("请输入密码:");
        String password = scanner.nextLine();
        return new User(username,password);
    }
}
/*
请输入用户名:
lyf
请输入密码:
lyf
输入正确的用户名和密码后会返回:登录成功
*/

上述两种方法都能实现客户端与服务器端之间的用户登录效果。

基于UDP协议的Socket编程

TCP和UDP之间的区别:

1、TCP协议通信双方需要建立连接,而UDP协议通信双方不需要建立连接。

2、TCP协议通信双方连接建立时双方存在主次之分,而UDP协议通信双方完全平等。

示例代码:

服务器端:

java 复制代码
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class UDPServer {

    public static void main(String[] args) throws Exception {

        DatagramSocket datagramSocket = new DatagramSocket(10001);
        byte[] buf = new byte[1024];
        //用来接收传输过来的数据
        DatagramPacket datagramPacket = new DatagramPacket(buf,buf.length);
        //利用创建好的数据报包对象来接收数据
        datagramSocket.receive(datagramPacket);
        //打印输出信息
        System.out.println(new String(datagramPacket.getData(),0,datagramPacket.getLength()));

        datagramSocket.close();
    }
}
// 接收客户端控制台上传输过来的数据并打印

客户端:

java 复制代码
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;

public class UDPClient {

    public static void main(String[] args) throws Exception {

        //创建udp通信的socket
        DatagramSocket datagramSocket = new DatagramSocket(10000);
        //从控制台读取数据
        Scanner scanner = new Scanner(System.in);
        String str = scanner.nextLine();
        DatagramPacket datagramPacket = new DatagramPacket(str.getBytes(),str.getBytes().length, InetAddress.getByName("localhost"),10001);
        datagramSocket.send(datagramPacket);

        datagramSocket.close();
    }
}
// 在客户端的控制台上输入数据
相关推荐
2401_857439691 分钟前
SpringBoot框架在资产管理中的应用
java·spring boot·后端
怀旧6663 分钟前
spring boot 项目配置https服务
java·spring boot·后端·学习·个人开发·1024程序员节
李老头探索5 分钟前
Java面试之Java中实现多线程有几种方法
java·开发语言·面试
芒果披萨10 分钟前
Filter和Listener
java·filter
qq_49244844615 分钟前
Java实现App自动化(Appium Demo)
java
阿华的代码王国23 分钟前
【SpringMVC】——Cookie和Session机制
java·后端·spring·cookie·session·会话
不爱学习的YY酱42 分钟前
【计网不挂科】计算机网络期末考试——【选择题&填空题&判断题&简述题】试卷(4)
网络·计算机网络
装睡的小5郎44 分钟前
家庭宽带如何开启公网ipv4和ipv6
网络
yfs10241 小时前
压缩Minio桶中的文件为ZIP,并通过 HTTP 响应输出
网络·网络协议·http
有谁看见我的剑了?1 小时前
Ubuntu 22.04.5 配置vlan子接口和网桥
服务器·网络·ubuntu