闭关修炼(十一)网络通信

你问我互联网工程设计学了啥?emm。。。感觉上课都在照着抄代码,要说什么印象特别深,脑海里还真没剩啥了。



网络通讯

IP

定位某台计算机

端口号

定位某个应用程序

客户端和服务端

发起请求端为客户端,发送响应端为服务端

TCP与UDP

什么是网络模型

4层,应用层(HTTP协议),传输层(TCP,UDP协议),网络层(IP协议),链路层(以太网协议)

任何计算机语言通讯,底层都使用socket技术

为什么socket支持这么多语言?

socket遵循一个二进制的端口号+IP的规范进行传输,所以可以跨语言使用。

socket核心协议:TCP和UDP

TCP和UDP的区别

UDP面向无连接 — 即不建立连接、限制传输64k的不可靠协议

TCP面向连接协议,三次握手后进行通讯,通过字节流进行传输,效率比UDP低,但比UDP靠谱。

什么是三次握手

当三次握手成功之后,才开始进行数据传输。

第一次握手:客户端:发送报文给服务端,SYN=J

第二次握手:服务端:发送报文给客户端,ACK=J+1,SYN=K

第三次握手:客户端:发送报文给服务端,ACK=K+1
在这里插入图片描述

什么是四次挥手

结束通信会进行四次挥手。

第一次挥手:客户端:发送FIN=M

第二次挥手:服务端:发送SYN=M+1

第三次挥手:服务端:发送FIN=N

第四次挥手:客户端:发送ACK=N+1

在这里插入图片描述
在这里插入图片描述

为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?

这是因为服务端的 LISTEN 状态下的 SOCKET 当收到 SYN 报文的建连请求后,它可以把 ACK 和 SYN(ACK 起应答作用,而 SYN 起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的 FIN 报文通知时,它仅仅表示对方没有数据发送给你了,但是你还可以给对方发送数据,也有这么种可能,你还有一些数据在传给对方的途中,所以你不能立马关闭连接,也即你可能还需要把在传输途中的数据给对方之后,又或者,你还有一些数据需要传输给对方后,(再关闭连接)再发送FIN 报文给对方来表示你同意现在可以关闭连接了,所以它这里的 ACK 报文和 FIN 报文多数情况下都是分开发送的。

UDP的客户端与服务端通讯例子

UDP核心是DatagramSocket和DatagramPacket。

服务端,用DatagramSocket+传入端口创建服务器,并且建立DatagramPacket来接收客户端的数据包

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

/**
 * udp服务器
 *
 * @author uuz
 * @date 2021/01/11
 */
public class UdpServer {
    /**
     * 端口号
     */
    static int PORT = 9009;

    /**
     * 缓冲区大小
     */
    static int BUFFER_SIZE = 1024;

    /**
     * 正在运行
     */
    static boolean IS_RUNNING = true;

    public static void main(String[] args) throws IOException {
        System.out.println("UDP SERVER IS RUNNING...");
        // 创建服务器端口号,默认使用本机ip
        DatagramSocket datagramSocket = new DatagramSocket(PORT);

        while (IS_RUNNING) {
            // 定义数据包
            byte[] buf = new byte[BUFFER_SIZE];
            DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length);

            // 接收客户端发来的数据,将数据封装给数据包,此方法阻塞接收
            datagramSocket.receive(datagramPacket);

            // 打印来源地址
            System.out.printf("来源IP地址: %s:%s\n内容: %s\n",
                    datagramPacket.getAddress(),
                    datagramPacket.getPort(),
                    new String(datagramPacket.getData(), 0, datagramPacket.getLength()));
        }
    }

}

客户端,构造DatagramPacket,传入服务器IP和端口,使用datagramSocket发送

import java.io.IOException;
import java.net.*;

public class UdpClient {
    static String REMOTE_ADDRESS = "127.0.0.1";
    public static void main(String[] args) throws IOException {
        System.out.println("新建Socket客户端");
        // 创建一个socket客户端
        DatagramSocket datagramSocket = new DatagramSocket();
        // 要发送的内容
        String content = "这是一条测试信息";
        // 转换成byte[]
        byte[] bytes = content.getBytes();
        // 创建数据包,带上要的发送IP和端口
        DatagramPacket dp = new DatagramPacket(bytes,
                bytes.length,
                InetAddress.getByName(REMOTE_ADDRESS),
                UdpServer.PORT);

        datagramSocket.send(dp);

        datagramSocket.close();
        System.out.println("发送UDP结束");
    }
}

TCP的客户端和服务端

服务器端

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

/**
 * tcp服务器
 *
 * @author uuz
 * @date 2021/01/11
 */
public class TCPServer {

    static int PORT = 8889;
    static int BUFFER_SIZE = 1024;
    static boolean isRunning = true;
    
    public static void main(String[] args) throws IOException {
        System.out.println("TCP SERVER START");
        // 创建服务器端口号
        ServerSocket serverSocket = new ServerSocket(PORT);
        while (isRunning) {
            // 阻塞接收信息
            Socket socket = serverSocket.accept();
            // 获取socket传输的字节流
            InputStream inputStream = socket.getInputStream();
            // 将字节流转为String
            byte[] bytes = new byte[BUFFER_SIZE];
            int length = inputStream.read(bytes);
            // 转换成String
            String data = new String(bytes, 0, length);
            // 打印输出
            System.out.println(data);
        }
        serverSocket.close();
    }
}

客户端

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

public class TCPClient {
    static String REMOTE_ADDRESS = "127.0.0.1";
    
    public static void main(String[] args) throws IOException {
        System.out.println("tcp 客户端");
        // 连接服务器
        Socket socket = new Socket(REMOTE_ADDRESS, TCPServer.PORT);
        // 获取字节流
        OutputStream outputStream = socket.getOutputStream();
        // 发送
        outputStream.write("这是一条测试".getBytes());
        // 关闭连接
        socket.close();
    }
}

服务端多线程版

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.SneakyThrows;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * tcp服务器
 *
 * @author uuz
 * @date 2021/01/11
 */
public class TCPServer {

    static int PORT = 8889;
    static int BUFFER_SIZE = 1024;
    static int THREAD_POOL_SIZE = 10;
    static boolean isRunning = true;

    public static void main(String[] args) throws IOException {
        System.out.println("TCP SERVER START");
        // 创建服务器端口号
        ServerSocket serverSocket = new ServerSocket(PORT);
        // 创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
        while (isRunning) {
            // 阻塞接收信息
            Socket socket = serverSocket.accept();
            executorService.execute(new Runnable() {
                @SneakyThrows
                @Override
                public void run() {
                    // 获取socket传输的字节流
                    InputStream inputStream = socket.getInputStream();
                    // 将字节流转为String
                    byte[] bytes = new byte[BUFFER_SIZE];
                    int length = inputStream.read(bytes);
                    // 转换成String
                    String data = new String(bytes, 0, length);
                    // 打印输出
                    System.out.println(data);
                }

            });
        }
        serverSocket.close();
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值