Java--TCP/UDP

网络通信的基础知识

  • IP:
    • IP是 Interent Protocol(国际互连协议的缩写),是TCP/IP协议中的网络层协议。
    • 想要让网络中的计算机实现通信,那么每个计算机必须有一个标识号,通过标识号来指定要接受信息的计算机以及要发送信息的计算机,这个标识号就是IP地址。(通俗的理解就如同生活中的手机号码)
    • IP地址的格式为xxx.xxx.xxx.xxx是很难记忆的,因此,我们会把IP地址转化为域名地址,方便记忆。
    • 本机IP地址为:127.0.0.1或localhost
  • 端口:
    • 我们知道计算机中由很多的进程,不同的进程需要不同的网络资源,那么就需要为每个进程分配固定的端口号。
    • 端口号的范围是:0-65535
  • 总结:要实现网络通信必须知道对方的IP地址以及端口号。

TCP和UDP

  • TCP(传输控制协议):
    • TCP协议是一种***面向连接、可靠的、基于字节流***的传输层通信协议。
  • UDP(用户数据报协议):
    • UDP协议是一种支持无连接的传输协议,它为应用程序提供了一种无需创建链接就可以发送数据报的方法。
  • TCP和UDP的区别
    • TCP是面向连接的,效率低;UDP不需要连接,速度快
    • TCP只能一对一的传输;UDP可以一对一、一对多、多对多、多对一的传输
    • TCP保证传输数据的正确性、有序性、不丢包、不重复;UDP不保证可靠性
    • TCP适合网络负担不大,可靠性要求高的场所;UDP适合网络负担重、响应高、客户端较多、可靠性要求不高的场景

Java中使用TCP协议进行传输

  • Java中要使用TCP传输就要使用socket套接字
  • socket套接字:具有唯一标识的IP地址和端口号
  • socket的原理机制:
    • 网络中的通信实际上是socket间的通信
    • 通信的两端计算机都有socket
    • 数据在两个socket之间通过IO流进行传输
  • socket传输的图解:
    Java--TCP/UDP_第1张图片
  • TCP传输的步骤:
    • 建立客户端和服务器端,客户端使用Socket,服务器端使用ServerSocket
    • 建立socket连接后使用IO流进行传输,客户端使用传出流,服务器端使用写入流接收,然后再使用管道流查看数据
    • 在传输完数据后要关闭所有的IO流以及socket
    • 启动时要先启动服务器端,再启动客户端
  • 演示客户端给服务器端发送信息:
客户端:
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

public class Clicent {
    public static void main(String[] args) throws Exception {
        //建立socket连接
        Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 6666);
        String msg = "你好,服务器!";
        //客户端给服务器端发送数据,那么就要读取客户端的数据,所以使用out
        OutputStream out = socket.getOutputStream();
        //tcp中的数据都是字节形式的
        out.write(msg.getBytes(),0,msg.getBytes().length);
        //关闭所有的流
        out.close();
        socket.close();
    }
}
===========================================
服务器端:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) throws IOException {
        //服务器端使用serversocket
        ServerSocket serverSocket = new ServerSocket(6666);
        //再使用accept方法来取得socket
        Socket socket = serverSocket.accept();
        InputStream in = socket.getInputStream();
        int len;
        byte[] bytes = new byte[1024];
        //使用管道流来查看数据
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        while ((len=in.read(bytes))!=-1){
            out.write(bytes,0,len);
        }
        System.out.println(out.toString());
        //关闭所有的流
        out.close();
        in.close();
        socket.close();
        serverSocket.close();
    }
}
  • 演示客户端给服务器端发送文件:
客户端:
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;

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


public class ClicentFile {
    public static void main(String[] args) throws Exception {
        //使用socket进行连接
        Socket socket = new Socket(InetAddress.getByName("localhost"), 5555);
        //读取文件
        FileInputStream file = new FileInputStream("test.txt");
        OutputStream out = socket.getOutputStream();
        byte[] bytes = new byte[1024];
        int len;
        while ((len = file.read(bytes)) != -1) {
            out.write(bytes, 0, len);
        }

        //服务器端接收到文件后会给客户端一个反馈,先关闭输出流
        socket.shutdownOutput();
        //打开输入流读取服务器端的信息
        InputStream in = socket.getInputStream();
        //管道流读取
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        int len1;
        byte[] bytes1 = new byte[1024];
        while ((len1=in.read(bytes1))!=-1){
            stream.write(bytes1,0,len1);
        }
        System.out.println(stream.toString());
        //关闭流
        out.close();
        file.close();
        stream.close();
        in.close();
        socket.close();
    }
}
=================================
服务器端:
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerFile {
    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket = new ServerSocket(5555);
        Socket socket = serverSocket.accept();
        InputStream in = socket.getInputStream();
        FileOutputStream out = new FileOutputStream("测试.txt");
        int len;
        byte[] bytes = new byte[1024];
        while ((len=in.read(bytes))!=-1){
            out.write(bytes,0,len);
        }
        //接收文件成功后给客户端一个反馈
        OutputStream stream = socket.getOutputStream();
        stream.write("我已经成功接收到文件!".getBytes());
        //关闭流
        out.close();
        in.close();
        stream.close();
        socket.close();
        serverSocket.close();
    }
}

Java中使用UDP协议进行传输

  • 使用UDP协议进行传输时,要使用DatagramSocket以及DatagramPacket
  • 使用DatagramSocket获取socket套接字
  • 使用DatagramPacket建立数据报
  • 传输完信息后把所有的流关闭
  • 发送端和接收端的演示:
发送端:
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class UdpSend {
    public static void main(String[] args) throws Exception {
        //1--使用datagramsocket获取socket
        DatagramSocket socket = new DatagramSocket();

        //声明要发送的数据
        String msg="这是UDP传输";

        //声明数据报
        DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, InetAddress.getByName("127.0.0.1"), 2333);

        //发送数据报
        socket.send(packet);

        //关闭流
        socket.close();
    }
}
===================================
接收端:
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class UdpResive {
    public static void main(String[] args) throws Exception {
        //1--使用datagramsocket获取socket
        DatagramSocket socket = new DatagramSocket(2333);

        //创建一个字节数组及datagrampacket接收数据报
        byte[] bytes = new byte[1024];
        DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length);

        //使用socket接收数据报
        socket.receive(packet);

        //使用packet中的getdata方法读取数据
        System.out.println(new String(packet.getData()));

        //关闭流
        socket.close();
    }
}

URL-统一资源定位符

  • URL是因特网的万维网服务程序上用于指定信息位置的表示方法。
  • 使用URL下载资源的实现步骤:
    • 声明一个URL对象,把资源所在的地址作为参数
    • 使用openconnection打开连接
    • 通过IO流来读写
    • 关闭所有的流
  • 通过URL下载网上资源的程序演示:

import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class URLDown {
    public static void main(String[] args) throws Exception {
        //1--声明一个url对象
        URL url = new URL("https://m10.music.126.net/20191203110348/27f448e1cd8fb89c7127d574eb6bfa67/yyaac/545a/0e0f/075c/c03b40b7be9e943eb5d006be88784114.m4a");

        //2--使用url打开连接
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();

        //3--读取数据
        InputStream in = urlConnection.getInputStream();

        //4--将文件写出
        FileOutputStream out = new FileOutputStream("C:\\Users\\Henry哼哼哼\\Desktop\\爱你不是两三天2.mp3");

        int len;
        byte[] bytes = new byte[1024];
        while ((len=in.read(bytes))!=-1){
            out.write(bytes,0,len);
        }

        //5--关闭所有的流
        out.close();
        in.close();
        urlConnection.disconnect();

    }
}

使用多线程发送数据

  • 我们在这里要让双方都可以发收数据,且对网络要求低,对数据的准确性也要求低,所以使用UDP协议
  • 代码演示:
发送端:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

public class Sender implements Runnable {

    private int toPort;
    private int fromPort;
    DatagramSocket socket = null;
    BufferedReader reader = null;

    public Sender(int toPort, int fromPort) throws SocketException {
        this.toPort = toPort;
        this.fromPort = fromPort;
        socket = new DatagramSocket(fromPort);
        reader = new BufferedReader(new InputStreamReader(System.in));
    }

    @Override
    public void run() {
        while (true) {
            try {
                String msg = reader.readLine();
                //声明数据报
                DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.length(), InetAddress.getByName("127.0.0.1"), toPort);
                //发送数据报
                socket.send(packet);
                //如果发送的内容是bye,则退出传输
                if (msg.equals("bye")) {
                    break;
                }
            } catch (SocketException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        //关闭流
        socket.close();
        try {
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
接收端:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class Resiver implements Runnable {
    private int port;
    private String name;
    DatagramSocket socket=null;
    public Resiver(int port, String name) throws SocketException {
        this.port = port;
        this.name = name;
        socket=new DatagramSocket(port);
    }

    @Override
    public void run() {
        while (true) {
            //使用datagramsocket获得socket
            try {
                byte[] bytes = new byte[1024];
                DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length);
                socket.receive(packet);
                byte[] data = packet.getData();
                String msg = new String(data, 0, data.length);
                System.out.println(name + ":" + msg);
                if (msg.equals("bye")){
                    break;
                }
            } catch (SocketException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //关闭流
    }
}
两个用户端:
import java.net.SocketException;

public class Teacher {
    public static void main(String[] args) throws SocketException {
        new Thread(new Sender(2222,6666)).start();
        new Thread(new Resiver(5555,"老师")).start();
    }
}
==========================
import java.net.SocketException;

public class Teacher {
    public static void main(String[] args) throws SocketException {
        new Thread(new Sender(2222,6666)).start();
        new Thread(new Resiver(5555,"老师")).start();
    }
}

你可能感兴趣的:(TCP,UDP,Socket,多人聊天)