第二十一章 网络通信

计算机网络实现了堕胎计算机间的互联,使得它们彼此之间能够进行数据交流。网络应用程序就是再已连接的不同计算机上运行的程序,这些程序借助于网络协议,相互之间可以交换数据,编写网络应用程序前,首先必须明确网络协议TCP/IP协议是网络应用程序的首选

4a4f2a9ac8e34647ad72104914e9a0fb.png

 网络程序设计基础:

网络程序设计编写始于其他计算机进行通信的程序,java已经将网络程序所需要而定元素封装成不同的类,用户只要床啊金这些类的对象,使用相应的方法即使不举报相关的网络知识,也是可以编写除高质量的网络通信程序的,

 

本章最主要的是TCP和UDP两个部分 他们两主要的区别就是一个是一对一通信 一个是一对多通信 当然两者都有各自的优势和劣势,接下来先讲解 TCP部分

 

TCP程序

TCP程序的通信方式呢 是一对一的 步骤是 先要打开服务器然后客户端连接服务器 先是尝试客户端是否能够接收到信息 如果可以接收到信息的话 这时服务器将会把文件传输给客户端,这样的话 能够保证客户端可以接收到信息 ,劣势呢就是每次都是要这样子 所以效率对比起UDP来说慢下了好多 以下代码将会进行讲解

客户端代码:

import java.io.*;

import java.net.Socket;

import java.util.Scanner;

 

/**

 * Socket客户端

 **/

public class SocketClient {

    public static void main(String[] args) {

        Socket s = null;

        try {

            // 与ip为127.0.0.1、端口为12345的服务端建立连接

            s = new Socket("127.0.0.1", 12345);

 

            // 创建输入流接收服务端发送的消息(字节流)

            InputStream is = s.getInputStream();

            // 将服务端返回的字节流转化为字符流

            InputStreamReader isr = new InputStreamReader(is);

            // 创建字符流读取缓冲区,方便每行读取

            BufferedReader br = new BufferedReader(isr);

 

            // 创建输出流返回消息

            OutputStream os = s.getOutputStream();

            // 创建输出流缓冲

            PrintWriter pw = new PrintWriter(os);

 

            // 创建发送消息的线程

            Runnable rOut = () -> {

                boolean flag = true;

                while (flag) {

                    try {

                        // 接收控制台输入

                        Scanner scan = new Scanner(System.in);

                        String msg = scan.nextLine();

                        // 将输入写入缓冲

                        pw.println(msg);

                        // 将缓冲内的数据推送至服务端并清空缓冲区

                        pw.flush();

                    } catch (Exception e) {

                        flag = false;

                        e.printStackTrace();

                    }

                }

            };

 

            // 创建接收消息的线程

            Runnable rIn = () -> {

                boolean flag = true;

                while (flag) {

                    try {

                        // 逐行读取服务端返回的消息并打印

                        String str = br.readLine();

                        System.out.println("服务端的消息:" + str);

                    } catch (IOException e) {

                        flag = false;

                        e.printStackTrace();

                    }

                }

            };

 

            // 启动两个线程

            Thread tOut = new Thread(rOut);

            Thread tIn = new Thread(rIn);

            tOut.start();

            tIn.start();

        }catch (IOException e) {

            try {

                // 释放资源

                s.close();

            } catch (Exception exception) {

                exception.printStackTrace();

            }

            e.printStackTrace();

        }

    }

}

服务端代码:


import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
 
/**
 * Socket服务端
 **/
public class SocketServer {
    public static void main(String[] args) {
        ServerSocket ss = null;
        Socket s = null;
        try {
            // 创建监听端口为12345的Socket服务端
            ss = new ServerSocket(12345);
            System.out.println("服务端Socket服务已建立,等待客户端连接...");
            // 通过ss.accept()开始持续监听12345端口,当有连接时获取收到的包装成Socket的客户端对象
            s = ss.accept();
            // 获取客户端的IP地址和端口号
            String ip = s.getInetAddress().getHostAddress();
            int port = s.getPort();
            System.out.println("服务端与 " + ip + ":" + port + " 已建立连接");
 
            // 创建输入流接收客户端发送的消息(字节流)
            InputStream is = s.getInputStream();
            // 将客户端发送的字节流转化为字符流
            InputStreamReader isr = new InputStreamReader(is);
            // 创建字符流读取缓冲区,方便每行读取
            BufferedReader br = new BufferedReader(isr);
 
            // 创建输出流返回消息
            OutputStream os = s.getOutputStream();
            // 创建输出流缓冲
            PrintWriter pw = new PrintWriter(os);
 
            // 创建接受信息的线程
            Runnable rIn = () -> {
                boolean flag = true;
                while (flag) {
                    try {
                        // 逐行读取客户端发送的消息并打印
                        String str = br.readLine();
                        System.out.println("客户端的消息:" + str);
                    } catch (IOException e) {
                        flag = false;
                        e.printStackTrace();
                    }
                }
            };
 
            // 创建发送消息的线程
            Runnable rOut = () -> {
                boolean flag = true;
                while (flag) {
                    try {
                        // 接收控制台输入
                        Scanner scan = new Scanner(System.in);
                        String msg = scan.nextLine();
                        // 将输入写入缓冲
                        pw.println(msg);
                        // 将缓冲内的数据推送至客户端并清空缓冲区
                        pw.flush();
                    } catch (Exception e) {
                        flag = false;
                        e.printStackTrace();
                    }
                }
            };
 
            // 开启两个线程
            Thread tIn = new Thread(rIn);
            Thread tOut = new Thread(rOut);
            tIn.start();
            tOut.start();
        } catch (IOException e) {
            try {
                // 释放资源
                ss.close();
                s.close();
            } catch (Exception exception) {
                exception.printStackTrace();
            }
            e.printStackTrace();
        }
    }
}

运行结果:

b65e0cf343ba40f88f74718fbc823b85.png

 接下来讲解UDP程序

UDP程序

UDP程序跟TCP程序不同的地方呢 TCP通信是一对一通信 如果要一下通知好多个人的话 就需要一个一个来通信 所以这时将会需要UDP了 UDP的优势就在于效率高 但是不稳定的地方呢 就是效率高但是不一定每个人都能看到 就像老师在台上讲课 总有一些学生会在台下玩手机 或者带耳机 不一定每一个人都能够接受得到 这就是UDP的不稳定的地方 ,接下来使用代码来讲解:

广播类代码如下:

 
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
//广播  先运行
public class Notification  extends Thread{
    String weather = "节目预报:八点有大型晚会,请收听";//发送消息
    int port = 9898;//端口号
    InetAddress iaddress = null;
    MulticastSocket socket = null;//多点广播套接字
    
    Notification(){
        try {
            iaddress = InetAddress.getByName("224.255.10.0");//地址
            socket = new MulticastSocket(port);//实例化多点广播套接字
            socket.setTimeToLive(1);//指定发送范围是本地网络
            socket.joinGroup(iaddress);//加入广播组
        }catch(IOException e){
            e.printStackTrace();//输出异常信息
        }
    
    }
    public void run(){//run方法
        while(true) {
            DatagramPacket packet = null;//数据包
            byte data[]=weather.getBytes();//字符串消息的字节数组
            packet =  new  DatagramPacket(data,data.length,iaddress,port);//将数据打包
            System.out.println(weather);//控制台打印消息
            try {
                socket.send(packet);//发送数据
                sleep(3000);//让线程休眠3000毫秒
            }catch(IOException e){
                e.printStackTrace();
            }catch(InterruptedException e) {
                e.printStackTrace();
            }
        }    
            }
    public static void main(String[]args) {
        Notification w =new Notification();
        w.start();//启动线程
    }
}

接收类代码如下:

import java.awt.BorderLayout;

import java.awt.Color;

import java.awt.GridLayout;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.io.IOException;

import java.net.DatagramPacket;

import java.net.InetAddress;

import java.net.MulticastSocket;

 

import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JPanel;

import javax.swing.JTextArea;

import javax.swing.WindowConstants;

//接收 后运行

public class Receive extends JFrame implements Runnable, ActionListener {

 int port ;//端口

 InetAddress group =null;//广播组地址

 MulticastSocket socket = null;//多点广播套接字对象

 JButton inceBtn = new JButton("开始接收");

 JButton stopBtn = new JButton("停止接收");

 JTextArea inceAr = new JTextArea(10,10);//显示接收广播的文本域

 JTextArea inced = new JTextArea(10,10);

 Thread thread ;

 boolean stop = false;//定制接受信息状态

 

 public Receive () {

  setTitle("广播数据包");

  setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

  thread = new Thread(this);

  inceBtn.addActionListener(this);//绑定按钮ince的单击事件

  stopBtn.addActionListener(this);//绑定按钮stop的单击事件

  inceAr.setForeground(Color.blue);//指定文本域中文字的颜色

  

  JPanel north = new JPanel();

  north.add(inceBtn);//将按钮添加到面板north上

  north.add(stopBtn);

  add(north,BorderLayout.NORTH);//将north放置在窗体的上部

  JPanel center = new JPanel();//创建面板对象center

  center.setLayout(new GridLayout(1,2));//设置面板布局

  center.add(inceAr);//将文本域添加到面板上

  center.add(inced);

  add(center,BorderLayout.CENTER);//设置面板的布局

  validate();//刷新

  port =9898;//设置端口号

  try {

   group = InetAddress.getByName("224.255.10.0");//指定接收地址

   socket = new MulticastSocket(port);//绑定多点广播套接字

   socket.joinGroup(group);//加入广播组

  }catch(IOException e){

   e.printStackTrace();//输出异常信息

  }

  setBounds(100,50,360,380);//设置布局

  setVisible(true);//将窗体设置为显示状态

 }

 public void run() {//run方法

  while (!stop) {

   byte data[] = new byte[1024];//创建缓存字节数组

   DatagramPacket packet = null;

   packet = new DatagramPacket(data,data.length,group,port);//待接收的数据包

   try {

    socket.receive(packet);//接收数据包

    //获取数据包中的内容

    String message = new String(packet.getData(),0,packet.getLength());

    inceAr.setText("正在接收的内容:\n"+message);//将接受内容显示在文本域中

    inced.append(message+"\n");//每条信息为一行

   }catch(IOException e ) {

    e.printStackTrace();//输出异常信息

   }

   

  }

 }

 public void actionPerformed(ActionEvent e) {//单机按钮ince出发时间

  if(e.getSource()==inceBtn) {

   inceBtn.setBackground(Color.red);//设置按钮颜色

   stopBtn.setBackground(Color.yellow);

   if(!(thread.isAlive())) {//如线程不处于“新建状态”

    thread = new Thread(this);//实例化Thread对象

   }

   thread.start();//启动线程

   stop = false;//开始接受信息

  }

  if(e.getSource()== stopBtn) {//单机按钮stop出发时间

   inceBtn.setBackground(Color.yellow);//设置按钮亚瑟

   stopBtn.setBackground(Color.red);

   stop = true;//停止接收信息

  }

 }

 public static void main(String[]args) {

  Receive rec = new Receive();

  rec.setSize(460,200);

 }

}

运行结果:e42f5062ade343edb1e76b0429cdc5ac.png

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值