java之网络编程

一、网络相关概念

1、认识网络

1.网络的概念和分类

简单来说,网络就是连接在一起共享数据和资源的一组计算机。

计算机网络旨在实现数据通信。如文本、图片或声音。

按照地理覆盖范围,计算机网络可以划分为局域网(LAN)、城域网(MAN)和广域网(WAN)。

2.网络分层模型

国际化标准组织(ISO)于1984年颁布了开放系统互连(OSI)参考模型。OSI参考模型是一个开放式体系结构,它规定将网络分为7层,每层在网络信息传递中都发挥不同的作用。还有一个TCP/IP五层模型。TCP/IP是传输控制协议/网络互连协议的简称。应用层对应OSI参考模型的最高3层(应用层、表示层、会话层),别的和OSI的一致。

 2、IP地址

1.IP地址自述

要实现两台计算机通信,双方都要有地址,在网络中使用一种具有层次结构的逻辑地址来标识一台主机,这个地址成为IP地址。IP地址是用来唯一标识网络中的每一台计算机。

IP地址目前存在IPv4和IPv6两种标准。

2.IP地址的组成和分类

(1)IP地址的组成

IPv4地址有32位,由4个8位的二进制数组成,每8位之间用圆点隔开,如11000000.10101000.00000010.00010100。但由于二进制不方便记忆,所以通常转换成十进制表示,如196.168.2.20。一个地址通常由用3个点号分开的4个十进制表示,称为点分十进制。

IPv6地址有128位,由8个16位的无符号整数组成,每个整数用4个16进制数表示,用:隔开。

(2)IP地址的分类

IP地址包含网络地址和主机地址两部分。其中,网络地址决定了可以分配的最大网络数,主机地址决定了一个网络中可以存在的计算机的最大数量。

 特殊地址:

0.0.0.0:表示本机。

127.0.0.1:表示本机回环地址,通常用在本机上ping此地址来检查TCP/IP协议安装是否正确。

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

(3)IP地址的分配和检测

1)打开“控制面板”窗口,找到“网络和共享中心”图标,点击。

2)找到“更改适配器设置”,如图

 3)第一个是你连接的无线网,右键选择属性,找到Internet协议版本4,双击,可以配置TCP/IP地址。

提示:一般电脑会默认自动获得IP地址,因为在一个局域网内,地址是不允许重复的,所以如果你固定了地址,那么很容易和别人的地址产生冲突,从而导致你网络连接不通。

配置完地址以后,可以查看自己的网络连接是否通畅。

 二、实现基于TCP协议的Socket编程

1、了解Socket

Socket相当于快递站点,不论发快递还是收快递都需要经过快递站点。

Socket的底层机制复杂,Java平台提供了一些简单的API,可以更简单有效的使用Socket开发而无需了解底层机制。

通信链路的端点就被称为“套接字”(英文名Socket)

是提供给应用程序的接口

java.net包提供了若干支持基于套接字的客户端 / 服务器通信的类。

Socket 、ServerSocket 、DatagramPacket、 DatagramSocket、 InetAddress等等。

2、基于TCP协议的Socket编程

java.net包的两个类Socket和ServerSocket,分别用来实现双向安全连接的客户端和服务器端,类似打电话,只有双方都接通了,才能开始通话。

2.1 实现单用户登录

先写一个用户类,存储用户信息,姓名、密码、性别、电话、发送的信息。注意要实现Serializable 接口,将信息序列化。

//帮我创建setter/getter方法,不会生成有参构造和无参构造
@Data
@AllArgsConstructor//生成有参构造
@NoArgsConstructor//生成无参构造
public class User implements Serializable {
    private String name;
    private String password;
    private String gender;
    private String phone;
    private String message;

}

服务器端类

public class LoginSocketTcp {
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(8081);//建立连接,监听端口号
            System.out.println("-----------------服务器服务器-------------------");
            Socket socket = serverSocket.accept();//使用accept方法等待客户端发起通信

            //打开输入输出流
            InputStream in = socket.getInputStream();
            //反序列化信息
            ObjectInputStream ois = new ObjectInputStream(in);
            User user = (User) ois.readObject();//读取客户端发送的信息,用User类型接收,此时需要进行强转。

            OutputStream os = socket.getOutputStream();

            //存储给客户端回复的信息
            String response = "";
            //判断用户信息账号密码是否正确,然后返回信息给客户端
            if ("班班".equals(user.getName()) && "123456".equals(user.getPassword())) {
                System.out.println("客户端登陆成功");
                System.out.println("客户端信息是:" + user);
                System.out.println("客户端发送的信息为:" + user.getMessage());
                response = "登录成功!允许使用服务器!";
            }else {
                response = "登录失败!账号或密码错误!";
            }
            //反馈信息给客户端,即向输入流中写入信息
            os.write(response.getBytes(StandardCharsets.UTF_8));
            //关闭资源
            os.flush();
            os.close();
            ois.close();
            in.close();
            socket.close();
            serverSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

客户端

public class LoginTcpTest {
    static Scanner sc = new Scanner(System.in);
    public static void main(String[] args) {
        try {
            //建立连接,指定服务器的位置为本机以及端口为8081
            Socket socket = new Socket("127.0.0.1",8081);
            System.out.println("------------------登录验证-------------------");

            //打开输入输出流
            OutputStream os = socket.getOutputStream();
            //序列化信息
            ObjectOutputStream oos = new ObjectOutputStream(os);//传对象用ObjectOutputStream

            InputStream is = socket.getInputStream();
            //获取服务器端回复的信息
            BufferedReader bf = new BufferedReader(new InputStreamReader(is));//为了使用readLine()方法读取服务器端回复的数据

            User user = new User("班班","123456","男","15286999596","错了,我是女生!");
            oos.writeObject(user);//将用户的信息传送给服务器端


            String info = bf.readLine();
            System.out.println(info);

            //关闭输入输出流
            bf.close();
            is.close();


            oos.flush();
            oos.close();
            os.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("连接到服务器失败!");
        }
    }
}

运行结果

服务器端

 客户端

 2.2 实现多客户端用户登录

        多客户端登录需要采用多线程的方式解决问题,可以在服务器端创建一个专门负责监听的应用主程序服务,一个专门负责相应的线程程序。

主程序代码

public class LoginThreadTest {
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        try {
            //建立一个服务器,指定端口并开始监听
            serverSocket = new ServerSocket(8081);
            System.out.println("-----------------服务器服务器-------------------");
            //使用accept方法等待客户端发起通信
            Socket socket = null;
            while (true){
                socket = serverSocket.accept();
                //将socket对象传进去
                LoginThread loginThread = new LoginThread(socket);
                Thread thread = new Thread(loginThread);
                thread.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

负责相应的线程程序

public class LoginThread implements Runnable{

    Socket socket = null;
    //每启动一个线程,连接对应的Socket
    public LoginThread(Socket socket){
        this.socket = socket;
    }
    //启动线程,即响应客户请求
    @Override
    public void run() {
        try {
            //打开输入输出流
            InputStream in = socket.getInputStream();
            OutputStream os = socket.getOutputStream();
            //反序列化信息
            ObjectInputStream ois = new ObjectInputStream(in);
            //获取客户端信息
            User user = (User) ois.readObject();
            //给客户端一个反馈
            String response = "";
            if ("班班".equals(user.getName()) && "123456".equals(user.getPassword())) {
                System.out.println("客户端登陆成功");
                System.out.println("客户端信息是:" + user);
                System.out.println("客户端发送的信息为:" + user.getMessage());
                response = "登录成功!允许使用服务器!";
            }else {
                response = "登录失败!账号或密码错误!";
            }
            os.write(response.getBytes(StandardCharsets.UTF_8));
            //关闭资源
            os.flush();
            os.close();
            ois.close();
            in.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

运行结果

客户1:

客户2:

 3、实现基于UDP协议的Socket编程

1.TCP和UDP的对比

TCP

UDP

是否连接

面向连接

面向非连接

传输可靠性

可靠

不可靠

速度

基于TCP的网络通信是安全的,是双向的,需要先建立连接,才开始数据通信。

基于UDP的网络通信,只需要指明对方地址,然后将数据送出去,并不会事先连接。

2.DatagramPacket类和DatagramSocket类

        java中有两个可使用的数据报实现通信的类,即DatagramPacket和DatagramSocket。DatagramPacket类起到数据容器的作用,DatagramSocket类用于发送或接收DatagramPacket。<二者的关系>

        DatagramPacket不提供发送或接收数据的类,而DatagramSocket提供send()和recive()方法,用于通过套接字发送和接收数据报。

3.基于UDP协议的Socket编程

服务器端

public class ServiceSocketUdp{
    public static void main(String[] args) {
        //定义byte数组存储接收的信息
        byte[] bytes = new byte[1024];
        //创建DatagramPacket对象,用来接收数据包
        DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
        try {
            //创建DatagramSocket对象,接收数据
            DatagramSocket socket = new DatagramSocket(8082);
            socket.receive(dp);
            System.out.println("已接收");
            //显示接收的信息
            String info = new String(bytes,0,bytes.length);
            System.out.println("客户端:"+ info);
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

客户端

public class ClientSocketUdp{
    public static void main(String[] args) {
        //要发送的信息
        String info = "小白兔,快开门!妈妈回来啦!";
        //使用byte数组存储信息
        byte[] bytes = info.getBytes(StandardCharsets.UTF_8);
        try {
            //获取本机主机地址
            InetAddress inetAddress = InetAddress.getByName("localhost");
            //创建DatagramSocket对象,向服务器发送信息
            DatagramSocket socket = new DatagramSocket();
            //创建DatagramPacket对象,封装要发送的信息
            DatagramPacket dp = new DatagramPacket(bytes, bytes.length,inetAddress,8082);
            //发送信息
            socket.send(dp);
            System.out.println("发送成功");
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

运行结果

客户端 

服务器端

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值