《java从入门到精通》——网络通信 2020-01-22 java学习笔记

19网络通信

19.1网络程序设计基础

  • 网络程序设计是指编写与其他计算机进行通信的程序

19.1.1局域网与因特网

  • Local Area Network,LAN 局域网 一群通过一定形式连接起来的计算机
  • Wide Area Network,WAN 由LAN延伸到更大范围
  • Internet 由无数LAN和WAN组成

19.1.2网络协议

网络协议规定了计算机之间连接的物理、机械、电子等特征以及计算机之间的相互寻址规则、数据发送冲突的解决、长的数据如何分段传送与接受等。

  1. IP协议
    • Internet Protocol,网络协议。在Internet网上存在数以亿计的计算机,每一台主机在网络上通过为其分配的Internet地址表示自己,这个地址就是IP地址。
    • IP地址占四个字节,32位二进制数,称为IPv4
    • TCP/IP 分4层,应用层、传输层、互联网层和主机到网络层,每层实现特定的功能,提供特定的服务和访问接口,并具有相对的独立性
  2. TCP与UDP协议
    • TCP (Transmission Comtrol) 传输控制协议,以固线连接为基础,数据抵达的排列顺序与发送顺序相同,适用于可靠性要求比较高的场合。HTTP\FTP\Telnet等场合
    • UDP(User Datagram Protocol) 用户数据报协议,无连接通信协议,不保证可靠数据传输,也不保证传输顺序,适用于准确性要求不高的场合,如网络聊天室、在线影片等。由于TCP协议在认证上存在额外耗费,有可能使传输速度变慢。UDP协议更适合对传输速度和时效要求非常高的网站。

19.1.3端口和套接字

  • 端口,一般而言是指计算机与网络的唯一的物理连接,网线插口。
  • 网络程序设计的端口是一个假想的连接装置,通过不同的端口确定连接到服务器的哪项服务上
  • 端口被规定位一个在0-65535之间的整数
  • 套接字(Socket)将应用程序与端口连接起来。假想的连接装置。java将套接字抽象为类,创建Socket类对象,即可使用套接字

19.2TCP程序设计基础

  • TCP网络程序设计是指利用Socket类编写通信程序。
  • 服务器程序ServerSocket
  • 客户机程序Socket

19.2.1InetAddress类

  • 与IP地址相关的类

  • package com.InternetCommunication;
    import java.io.*;
    import java.net.*;
    public class Address {
        public static void main(String[] args) {
            InetAddress ip;
            try{
                ip=InetAddress.getLocalHost();//实例化对象
                String localname=ip.getHostName();
                String localip=ip.getHostAddress();
                System.out.println("本机名:"+localname);
                System.out.println("本机名:"+localip);
    
            }catch (UnknownHostException e){//UnknownHostException
                // 主机不存在或网络连接错误时发生
                e.printStackTrace();
            }
        }
    }
    
    

19.2.2ServerSocket类

  • 表示服务器套接字

  • 主要功能:等待来自网络上的“请求”,可通过指定的端口来等待连接的套接字,依次可以与一个套接字连接

  • 如果多台客户机同时提出连接请求,服务器套接字会将请求连接的客户机存入队列,(队列默认大小为50,大于最大容纳数多余请求被拒绝),然后从中取出一个套接字,与服务器新建的套接字连接起来

  • ServerSocket()

  • ServerSocket(int port)

  • accept()方法会堵塞线程的执行,直到接收到客户的呼叫

  • 如果没有客户呼叫,线程也没堵塞,则是程序出了问题,通常是使用了一个还在被其他应用程序占用的端口号,ServerSocket绑定没有成功

19.2.3TCP网络程序

  • 单向通信

  • //服务器端
    package com.InternetCommunication;
    
    import java.io.*;
    import java.net.*;
    
    public class MyTcp {//创建类MyTCP
        private BufferedReader reader;//创建BufferedReader对象
        private ServerSocket server;//创建ServerSocket对象
        private Socket socket;//创建socket对象socket
        void getserver(){
            try{
                server=new ServerSocket(8998);
                System.out.println("服务器套接字已经创建成功");
                while(true){
                    System.out.println("等待客户机的连接");
                    socket=server.accept();
                    reader= new BufferedReader(new InputStreamReader(socket.getInputStream()));//三层包装,又称过滤器,可以嵌套,看你想用什么方法,本例用了带缓冲区的字节读入流。
                    getClientMessage();
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        private void getClientMessage(){
            try{
                while(true){
                    System.out.println("客户机:"+reader.readLine());
                }
            }catch (Exception e){
                e.printStackTrace();
            }
            try{
                if(reader !=null){
                    reader.close();
                }
                if(socket !=null){
                    socket.close();
                }
            }catch (IOException e){
                e.printStackTrace();
            }
        }
        public static void main(String[] args) {
            MyTcp tcp=new MyTcp();
            tcp.getserver();
        }
    }
    
    
  • //客户端
    package com.InternetCommunication;
    import java.awt.*;
    import java.awt.event.*;
    import java.io.*;
    import java.net.*;
    import javax.swing.*;
    public class MyClient extends JFrame {
        private PrintWriter writer;
        Socket socket;
        private JTextArea ta=new JTextArea();
        private JTextField tf=new JTextField();
        Container cc;
        public MyClient(String title){
            super(title);
            cc=this.getContentPane();
            cc.add(ta,"North");
            cc.add(tf,"South");
            tf.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    writer.println(tf.getText());
                    ta.append(tf.getText()+'\n');
                    tf.setText("");
                }
            });
        }
        private void connect(){
            ta.append("尝试连接");
            try{
                socket=new Socket("192.168.124.12", 13422);//实例化Socket对象
                writer=
                        new PrintWriter(socket.getOutputStream(),true);
                ta.append("完成连接");
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        public static void main(String[] args) {
            MyClient Client=new MyClient("向服务器送数据");
            Client.setSize(200,200);
            Client.setVisible((true));
            Client.connect();//调用连接方法
        }
    }
    
    

    netstat -an 可以在命令行中查看端口使用情况

19.3UDP程序设计基础

  • 基本模式:

    • 将数据打包(称为数据包),然后将数据包发往目的地;

    • 接受别人发来的数据包,然后查看数据包

    • UDP程序的步骤

      1. 使用DatagramSocket()创建一个数据包套接字
      2. 使用DatagramPacket(byte[] buf,int offset,int length,InetAddress address,int port)创建要发送的数据包
      3. 使用DatagramSocket类的send()方法发送数据包。

      接受数据包

      1. 使用DatagramSocket(int port)创建数据包套接字,绑定到指定的端口
      2. 使用DatagramPacket(byte[] buf,int length)创建字节数组来接受数据包
      3. 使用DatagramPacket类的receive()方法来接受UDP包
    • DatagramPacket类的receive()方法接收数据时没有可接受的数据时方法将阻塞,一直等到网络上有数据到来。

    • 如果没有数据到来,receive()方法也没有阻塞,肯定是程序有问题,多半是使用了被其他程序占用的端口号。

19.3.1DatagramPacket类

  • 构造函数: 表示数据包

  • - DatagramPacket(byte[] buf,int length)//数据包的内存空间和大小
    - DatagramPacket(byte[] buf,int length,InetAddress,int port)//数据包的内存空间和大小,数据包的目标地址和端口号,创建了可发送数据的DatagramPacket
    

19.3.2DatagramSocket类

  • 构造函数: 发送和接受数据包的套接字

  • DatagramSocket()//创建数据包套接字,并将其绑定到本地主机上的任何可用端口
    DatagramSocket(int port)//创建数据包套接字,并将其绑定到本地主机上的指定端口
    DatagramSocket(int port,InetAddress addr)//创建数据包套接字,并将其绑定到指定的本地地址,适用有多块网卡和多个IP的情况
    
  • 接收程序时指定端口号,发送程序时不指定端口号

19.3.3UDP网络程序

  • //广播数据报程序
    package com.InternetCommunication;
    import java.io.IOException;
    import java.net.*;
    public class Weather extends Thread{
        String weather="节目预报:八点有大型晚会,请收听";
        int port=9898;
        InetAddress iaddress=null;
        MulticastSocket socket=null;
        Weather(){
            try{
                iaddress=InetAddress.getByName("224.255.10.0");
                //组播地址用 netsh interface ipv4 show joins命令去命令提示符查找
                socket=new MulticastSocket(port);
                socket.setTimeToLive(1);
                socket.joinGroup(iaddress);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        public  void run(){
            while (true){
                DatagramPacket packet=null;
                byte data[]=weather.getBytes();
                packet=new DatagramPacket(data,data.length,iaddress, port);
                System.out.println(new String(data));
                try{
                    socket.send(packet);
                    sleep(2000);
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
    
        public static void main(String[] args) {
            Weather w=new Weather();
            w.start();
        }
    }
    
    
  • //接收广播程序
    package com.InternetCommunication;
    import java.io.IOException;
    import java.net.*;
    import javax.swing.*;
    import java.awt.*;
    import java.lang.*;
    import java.awt.Container;
    import java.awt.event.*;
    import java.awt.event.ActionListener;
    import java.net.DatagramPacket;
    import java.net.InetAddress;
    import java.net.MulticastSocket;
    
    public class Receive extends JFrame implements Runnable, ActionListener {
        int port;
        InetAddress group = null;
        MulticastSocket socket = null;
        JButton ince = new JButton("开始接受");
        JButton stop = new JButton("停止接收");
        JTextArea inceAr = new JTextArea(10, 10);
        JTextArea inced = new JTextArea(10, 10);
        Thread thread;
        boolean b = false;
    
        public Receive() {
            super("广播数据报");
            thread = new Thread(this);
            ince.addActionListener(this);
            stop.addActionListener(this);
            inceAr.setForeground(Color.blue);
            JPanel north = new JPanel();
            north.add(ince);
            north.add(stop);
            add(north, BorderLayout.NORTH);
            JPanel center = new JPanel();
            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 (Exception e) {
                e.printStackTrace();
            }
            setBounds(100,50,360,380);
            setVisible(true);
        }
    
        public void run() {
            while (true) {
                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 (Exception e) {
                    e.printStackTrace();
                }
                if (b == true) {
                    break;
                }
    
            }
        }
    
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() == ince) {
                ince.setBackground(Color.red);
                stop.setBackground(Color.yellow);
                if (!(thread.isAlive())) {
                    thread = new Thread(this);
                }
                thread.start();
                b = false;
            }
            if (e.getSource() == stop) {
                ince.setBackground(Color.yellow);
                stop.setBackground(Color.red);
                b = true;
            }
        }
    
        public static void main(String[] args) {
            Receive rec = new Receive();
            rec.setSize(460, 200);
        }
    }
    
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值