java基础:网络通信TCP/IP、UDP协议知识。

一、TCP协议

   TCP协议是面向连接的协议,在数据传输之前会首先建立逻辑连接,然后在传输数据,可保证数据的无差错数据传输,TCP连接中必须明确客户端和服务端,由客户端向服务端发起连接请求,每次创建连接都要经过三次握手。①客户端向服务端发出请求,②服务端响应客户端,通知客户端已收到请求。③客户端再次向服务端发送确认信息,确认连接。

客户端 服务端 [SYN], Seq=0, Len=0 [SYN,ACK], Seq=0,Ack=1, Len=0 [ACK], Seq=1,Ack=1, Len=0 客户端 服务端

TCP相关类的使用:

  1. ServerSocket类
      用于表示服务端。
      构造函数:
    ①ServerSocket()
      不带参的默认构造方法,因为没有绑定端口,需要调用bind(SocketAddress endpoint)方法绑定端口才可正常使用。
    ②ServerSocket(int port)
      创建对象时指定端口号,指定为0时系统会自动分配一个没有被占用的端口号。
    ③ServerSocket(int port,int backlog)
      比第二个方法多了一个backlog参数,指在服务器忙时保持连接请求的等待客户数量,不指定默认为50。
    ④ServerSocket(int port,int backlog,InetAdress bindAddr)
      比第三个方法多了一个bindAddr参数,用于指定ip地址,一般用于多网卡多IP的场景。
    常用方法:

     Socket accept()//等待客户连接,在客户连接之前会一直处于连接状态,若有客户连接则返回一个与之对应的Socket。
     InetAdress getInetAdress()//返回InetAdress对象,对象中封装了ServerSocket封装的IP地址。
     boolean isClosed()//判断ServerSocket对象状态,关闭返回true,打开返回false.
     void bind(SocketAddress endpoint)//绑定IP地址与端口号。
    
  2. Socket类
      用于表示客户端。
      构造函数:
    ①Socket()
      创建对象时没有指定ip与端口号,使用还需要调用connect(SocketAddress endpoint)方法,才能与指定的服务端连接,endpoint封装ip与端口号。
    ②Socket(String host, int port)
      创建对象时指定IP与端口号,host为字符串IP。
    ③Socket(InetAddress address, int port)
      与前一个方法区别在于ip地址是使用InetAddress封装。
      常用方法:

     int getPort()//返回与服务端连接的端口号。
     InetAddress getLocalAddress()//获取Socket绑定的本地IP地址。
     void close()//释放资源.
     InputStream getInputStream()//返回输入流对象,如果是由服务端的Socket返回,则用于读取客户端数据,反之,则读取客户端数据。
     OutputStream getOutputStream()//返回输出流对象,若是有服务端的Socket返回,则用于向客户端发送数据,反之则用于向服务端发送数据。
    

  使用案例:

客户端:

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

public class T_Client {
    public static void main(String[] args) throws IOException {
    new TCPClient().connect();
    }
}
//TCP客户端
class TCPClient{
    private static final int PORT = 7001;
    public void connect() throws IOException {

            //创建Socket对象
            Socket client = new Socket(InetAddress.getLocalHost(),PORT);

            //给服务端发送信息
            OutputStream op =client.getOutputStream();
            String str ="hello Server...";
            op.write(str.getBytes("UTF-8"));
            //关闭输出流,表示发送完成
            client.shutdownOutput();

            //读取服务端发送的数据
            InputStream is = client.getInputStream();
            byte[] buf = new byte[1024];
            int len = is.read(buf);
            System.out.println(new String(buf,0, len));
            client.close();
    }
}

服务端:

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

public class T_Server {
    public static void main(String[] args) throws IOException, InterruptedException {
        new TCPServer().listen();
    }
}
class TCPServer{
    private static final int PORT = 7001;
    public void listen() throws IOException, InterruptedException {
        ServerSocket serverSocket = new ServerSocket(PORT);
        while (true){
            //accept(),监听客户端
            Socket client = serverSocket.accept();
            //使用线程,同时处理多个客户端请求
           new Thread(){
               @Override
               public void run() {
                    try {
                        System.out.println("开始与客户端交互数据");

                        //读取服客户发送的数据
                        InputStream is = client.getInputStream();
                        byte[] buf = new byte[1024];
                        int len = is.read(buf);
                        System.out.println(new String(buf,0, len));

                        //获取输出流,给客户端返回消息
                        OutputStream os = client.getOutputStream();
                        os.write("hello 早上好".getBytes());
                        Thread.sleep(10000);
                        System.out.println("交互结束");
                        os.close();
                        client.close();
                    } catch (IOException | InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }.start();
        }

    }
}

二、UDP协议

  UDP协议是无连接通信的协议,发送数据时发送端和接收端不建立逻辑连接,即在发送数据时发送端不会确认接收端是否存在,只管发送数据,不确定数据是否送达,而接收端接收到数据时也不会返回信息给发送端。相较于TCP,UDP协议消耗的资源较小,通信效率高,通常都会用在一些视频、音频的传输和一些允许数据丢失的场景使用,因为UDP协议不能确保数据的完整性,是不可靠的传输,在传输重要数据时不推荐使用UDP协议。

UDP相关类的使用:

  1. DatagramPacket类
      该类用于封装UDP传输的发送或者接收的数据包。
      构造函数:
       ①DatagramPacket(byte[] buf, int length)
          该方法只指定了字节数组与数据大小,没有ip地址和端口号,因为不知道目的地址的ip和端口号,所以不能用于发送端
       ②DatagramPacket(byte[] buf, int offset, int length)
          该方法比上一方法多了一个offset参数,指接收到的数据放入buf缓冲区时从offset处开始。
       ③DatagramPacket(byte[] buf, int length, InetAddress addr, int port)
         该方法指定了字节数组、数据大小、ip、端口号。明确目的地址,所以一般用于发送端
       ④DatagramPacket(byte[] buf, int offset, int length, InetAddress addr, int port)
         该方法比上一个方法多了一个偏移量offset,指从数组offset位置开始发送数据。
      常用方法:

     InetAddress getAddress()//返回IP地址,如果是发送端的对象,则返回接收端的IP地址(目的IP),反之则返回发送端的IP。
     int getPort()//返回端口号,如果是发送端,则返回接收端的端口号(目的端口号),相反则返回发送端的端口号。
     byte[] getData()//返回数据,如果是发送端,则返回将要发送的数据,如果是接收端,则返回接收的数据。
     int getLength()//返回数据长度,接收和发送端都可用。
    
  2. DatagramSocket类
      该类用于实现数据的发送与接收。
      构造函数:
      ①DatagramSocket()
        该方法没有指定端口号,使用时系统会分配一个没有被占用的端口号,一般用于发送端。
      ②DatagramSocket(int port)
        该方法指定了端口号,可以发送、接收。
      ③②DatagramSocket(int port, InetAddress addr)
        该方法指定了端口号、ip地址,可以发送、接收,可用在多网卡的场景。
      常用方法:

     void receive(DatagramPacket p)//将接收到的数据填充到DatagramPacket数据包,收到数据前会一直阻塞,当接收到数据时才会返回。 
     void send(DatagramPacket p)//用于发送DatagramPacket数据包,发送的数据要包含数据、长度、ip地址、端口号。
     void close()//释放资源。
    

  使用案例:

public class T_UDP {
    public static void main(String[] args) {
    new Receiver().start();
    new Send().start();
    }
}

//线程,负责接收
class Receiver extends Thread{
    @Override
    public void run() {
        try {
            DatagramSocket ds = new DatagramSocket(8002);
            DatagramPacket dp = new DatagramPacket(new byte[1024],1024);
            //一直接收
            while (true){
                ds.receive(dp);
                byte[] arr =  dp.getData();//创建byte数据接收数据
                int len = dp.getLength();   //获取数据长度
                String ip = dp.getAddress().getHostAddress();//获取IP地址
                System.out.println("ip:"+ip+new String(arr,0, len));//显示数据
            }
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
//发送端
class Send extends Thread{
    @Override
    public void run() {
        try {
            DatagramSocket ds = new DatagramSocket();//实例化DatagramSocket
            Scanner sc = new Scanner(System.in);//输入扫描器
            while (true){
                String str = sc.nextLine();
                if("quit".equals(str)){//遇到quit字符串退出
                    break;
                }
                DatagramPacket dp = new DatagramPacket(str.getBytes(),str.getBytes().length,InetAddress.getByName("localhost"),8002);//发送数据
                System.out.println("发送数据");
                System.out.println(dp.getAddress());
                ds.send(dp);
            }
            ds.close();//释放资源
        } catch (SocketException | UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

三、UDP与TCP的差异

  UDP只有发送端与接收端,不区分客户端与服务端,相互之间可以任意的发送数据。而TCP是严格区分客户端与服务端的,通信时,必须由客户端去连接服务端才能实现通信,服务端不能主动连接客户端,且服务端需要先运行,等待客户端的连接。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值