网络编程(java)

1 - 概述

1.1 - 网络编程的三要素

1、IP地址

2、端口

3、协议

1.2 - IP地址

IP地址就是设备(电脑、手机、平板、冰箱、空调、台灯)在网络中的唯一标识(通过IP地址访问设备)

  • IP地址的两大分类

    • IPV4(主流的网络地址格式)

    • IPV6

  • DOS命令

    • ipconfig -all

    • ping xxx.xxx.xxx.xxx

    • netstat -ano

  • 特殊的IP地址

    • 127.0.0.1 - 本地的回环地址

1.3 - InetAddress

import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * @author Mr.乐
 * @Description InetAddress
 */
public class Demo01 {
    public static void main(String[] args) throws UnknownHostException {
         //将ip地址转换为一个对象
//        InetAddress address = InetAddress.getByName("故离");//通过主机名获取
         InetAddress address = InetAddress.getByName("127.0.0.1");  //通过回环地址获取
        //        InetAddress address = InetAddress.getByName("192.168.8.1"); // 外网地址
        System.out.println(address);
        //获取进程所在机器的计算机的名字
        System.out.println(address.getHostName());
        //获取主机的IP地址
        System.out.println(address.getHostAddress());
    }
}

1.4 - 端口

端口就是一个应用程序(进程/线程)在设备(本机)中的唯一标识

端口号:用两个字节的整数来表示的(unsigned short:0~65535),其中0 ~ 1024之间的端口号尽量不要使用,因为很多知名的网络服务商都会在这个范围内选择端口号(被占用的几率比较大),建议使用10000以上。如果被占用的话,再换一个。

1.5 - 协议

计算机网络中,连接和通信的规则

  • UDP

    • User Datagram Protocol 用户数据包协议

    • UDP协议是一种无连接的通信协议,即在数据传输的时候,数据的发送端和接收端不会建立所谓的逻辑连接,简单来说就是一台计算机向另一台极端及发送数据时,发送端不会确认接收端是否存在,都会将数据发送出去。同样接收端也不会向发送端反馈任何的接收数据的内容。

  • UDP协议消耗的资源相对来说较小,通信效率很高,但是不安全的。

  • TCP

    • Transmission Control Protocol 传输控制协议

    • TCP协议是一种面向连接/安全的通信协议,在数据传输之前,发送端和接收端会各自创建一个逻辑连接,然后再进行数据传输。

2 - UDP通信

2.1 - 通信原理

UDP在通信的时候在两端各自创建一个Socket(套接字)对象,但是这两个Socket只是用来发送和接收数据的对象,因此对于UDP协议通信的双方而言,没有所谓的客户端和服务器端。

2.2 - UDP发送

  • 发送的步骤

    1、创建发送端的Socket对象 - DatagramSocket

    2、创建数据,并把数据打包

    3、调用发送方法 - send

    4、关闭发送

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

/**
 * @author Mr.乐
 * @Description  UDP发送端
 */
public class UDPSend {
    public static void main(String[] args) throws IOException {
        //1、创建发送端的Socket对象 -  DatagramSocket
        DatagramSocket socket=new DatagramSocket();
        // 2、创建数据,并把数据打包
        byte[] bytes = "Hello UDP Send Messages!".getBytes();
        int length = bytes.length;
        InetAddress address = InetAddress.getByName("127.0.0.1");
        int port=1314;
        DatagramPacket packet=new DatagramPacket(bytes,length,address,port);
        //3、调用发送方法  -  send
        socket.send(packet);
        // 4、关闭发送
        socket.close();
    }
}

2.3 - UDP接收数据

  • 接收数据的步骤

    1、创建接收端的Socket对象

    2、创建一个数据包,用于接收数据

    3、调用接收方法 - receive

    4、解析数据包

    5、关闭接收

import java.net.DatagramPacket;
import java.net.DatagramSocket;

/**
 * @author Mr.乐
 * @Description UDP接收数据
 */
public class UDPReceive {
    public static void main(String[] args) throws Exception {
        //        1、创建接收端的Socket对象
        DatagramSocket ds = new DatagramSocket(1314);
      //  2、创建一个数据包,用于接收数据
        byte[] bytes = new byte[1024];//创建接收数据缓冲区,如果实际数据长度超过了范围,则会被截断
        DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
      // 3、调用接收方法 -  receive
        ds.receive(dp);
      //  4、解析数据包
        byte[] data = dp.getData();//获取数据包中的数据
        int length = dp.getLength();//获取发送过来的数据的实际长度
        String str = new String(data, 0, length);//将数据转换成字符串
        System.out.println(str);
     // 5、关闭接收
        ds.close();
    }
}

2.4 - 案例

需求

1、UDP发送数据:数据来源于键盘输入,直到输入over的时候就结束数据的发送

2、UDP接收数据:因为不知道发送端什么时候停止发送,所以使用死循环接收数据

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
 * @author Mr.乐
 * @Description   发送端获取键盘输入发送数据
 */
public class UDPSend {
    public static void main(String[] args)throws Exception {
        DatagramSocket ds = new DatagramSocket();//创建Socket对象

        //自己封装的标准键盘输入流
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String line;

        while ((line = br.readLine()) != null){
            if("over".equals(line))
                break;
            //如果用户输入的不是over,则需要把数据打包发送到接收端
            byte[] bytes = line.getBytes();
            int length = bytes.length;
            InetAddress address = InetAddress.getByName("127.0.0.1");
            int port = 9527;
            DatagramPacket dp = new DatagramPacket(bytes, length, address, port);//打包发送的数据
            ds.send(dp);//发送数据
        }
        ds.close();//关闭对象
    }
}
----------------------------------------------------------------------------
import java.net.DatagramPacket;
import java.net.DatagramSocket;

/**
 * @author Mr.乐
 * @Description 接收端循环接收数据
 */
public class UDPReceive {
    public static void main(String[] args) throws Exception {
        DatagramSocket ds=new DatagramSocket(9527);
        while (true){
            byte[] bytes = new byte[1024];//创建数据缓冲区
            DatagramPacket dp = new DatagramPacket(bytes, bytes.length);//创建数据包用来接收数据
            ds.receive(dp);//接收数据
            System.out.println("接收到:" + new String(bytes,0,dp.getLength()));
        }
    }
}

3 - TCP通信

3.1 - TCP通信原理

TCP通信是一种可靠的网络编程协议,它会在通信的两端各自创建一个Socket对象,从而在通信的两端形成虚拟的网络连接,一旦建立了这种网络间接,两端的程序就可以通过网络IO流来进行数据的通信。

3.2 - TCP的数据发送

  • 发送步骤

    1、创建客户端的Socket对象 - Socket

    2、获取输出流

    3、写数据

    4、释放资源

import java.io.OutputStream;
import java.net.Socket;

/**
 * @author Mr.乐
 * @Description 客户端发送数据
 */
public class TCPSend {
    public static void main(String[] args) throws Exception {
        //创建Socket对象
        Socket socket = new Socket("127.0.0.1", 1314);
        //通过Socket对象获取输出流
        OutputStream os = socket.getOutputStream();
        //通过输出流对象写数据,
        os.write("Hello TCP Send Messages!~".getBytes());
        //释放资源
        socket.close();
        os.close();
    }
}

3.3 - 服务器端接收数据

  • 接收数据的步骤

    1、创建服务器端的Socket对象 - ServerSocket

    2、获取通信用的Socket对象

    3、获取输入流

    4、读数据

    5、处理数据

    6、释放资源

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

/**
 * @author Mr.乐
 * @Description TCP服务器端接收数据
 */
public class TCPReceive {
    public static void main(String[] args) throws Exception {
        //1、创建服务器端的Socket对象 - ServerSocket
        ServerSocket serverSocket = new ServerSocket(1314);
        //    2、获取通信用的Socket对象
        Socket socket = serverSocket.accept();//等待请求被连接,阻塞式方式,获取用来通信的socket对象
        //    3、获取输入流
        InputStream is = socket.getInputStream();
        //     4、读数据
        byte[] bytes = new byte[1024];
        int length = is.read(bytes);//通过输入流读数据,返回的是实际数据的的长度
        //      5、处理数据
        String data = new String(bytes, 0, length);
        System.out.println("接收到客户端发来的消息:" + data);
        //    6、释放资源
        serverSocket.close();
        socket.close();
        is.close();
    }
}

3.4 - 模拟聊天室

 

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Set;

/**
 * @author Mr.乐
 * @Description 转发服务器
 */
public class Server {
    public static void main(String[] args) throws Exception {
        //创建UDP接收和发送对象
        DatagramSocket dsSend = new DatagramSocket();//发送对象
        DatagramSocket dsRec = new DatagramSocket(1314);//接收对象

        byte[] bytes = new byte[1024];//创建聊天数据缓冲区
        //接收并转发数据
        while (true){
            //创建接收数据包
            DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
            //接收数据
            dsRec.receive(dp);//接收到数据后,将数据转发给其它客户端
            int length = dp.getLength();//接收到的数据的实际长度
            InetAddress address = InetAddress.getByName("127.0.0.1");//IP地址
            //转发给每个端口号,获取客户端的端口号
            Set portSet = Global.portMap.keySet();
            for (Integer port : portSet) {
                dsSend.send(new DatagramPacket(bytes,length,address,port));
            }
            System.out.println("已成功转发一条信息");
        }
    }
}
---------------------------------------------------------------------
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
 * @author Mr.乐
 * @Description
 */
public class Send implements Runnable{
    @Override
    public void run() {
        try {
            //创建发送的Socket对象
            DatagramSocket ds = new DatagramSocket();
            //封装一个键盘输入流
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            String line;
            while((line=br.readLine())!=null){
                if ("exit".equals(line))
                    System.exit(0);//如果用户输入exit,直接结束程序
                byte[] bytes = (Thread.currentThread().getName() + "##@@##" + line).getBytes();
                DatagramPacket dp=new DatagramPacket(bytes,bytes.length,
                        InetAddress.getByName("127.0.0.1"),1314);
                ds.send(dp);//发送数据
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
--------------------------------------------------------------
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

/**
 * @author Mr.乐
 * @Description
 */
public class Receive implements Runnable{
    //定义端口号用于接收线程接收数据
    private Integer port;

    public Receive(Integer port){
        this.port = port;
    }
    @Override
    public void run() {
        try {
            DatagramSocket ds=new DatagramSocket(port);
            System.out.println(Thread.currentThread().getName() + "- 登录成功!~");
            while(true){
                //创建接收数据缓冲区
                byte[] bytes = new byte[1024];
                //创建接收数据包
                DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
                ds.receive(dp);//接收数据
                //此时接收到的信息的格式:用户名##@@##信息
                String recStr = new String(bytes, 0, dp.getLength());
                //拆分成用户名和信息的字符数组
                String[] info = recStr.split("##@@##");
                //如果发送了空的信息,可能没有info[1]的成员
                String mes = info.length > 1 ? info[1] : "";
                //过滤自己发送的信息字节接收,并且同时保证信息不为空
                if(!Thread.currentThread().getName().equals(info[0]) && !mes.equals("")){
                    System.out.println("接收到 - " + info[0] + "->" + mes);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
----------------------------------------------------------------------
import java.util.Scanner;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author Mr.乐
 * @Description 客户端类
 */
public class ChatRoomRun {
    public static void main(String[] args) {
//提示用户登录,获取用户序号
        int index = getUser();
        int port = 20000 + index;//获取用户对应的端口号
        //获取用户名
        String userName = Global.portMap.get(port);
        Thread sendThread = new Thread(new Send(), userName);//创建发送线程
     Thread recThread = new Thread(new Receive(port), userName);//创建接收线程

        //开启线程
        sendThread.start();
    recThread.start();
    }
    private static int getUser() {
        System.out.println("用户列表如下:");
        Set portSet = Global.portMap.keySet();//获取端口号的集合
        int index = 1;
        for (Integer port : portSet) {
            System.out.println(index++ + ":" +Global.portMap.get(port));
        }
        do{
            System.out.println("请输入正确的用户序号:");
            index = new Scanner(System.in).nextInt();//获取用户输入的序号
        }while (index < 1 || index > 4);
        return index;
    }
}

你可能感兴趣的:(网络,java,intellij-idea)