【网络原理】网络编程Socket套接字基础知识汇总

简介: 【网络原理】网络编程Socket套接字基础知识汇总

1.网络初始:

  1. 局域网(LAN)广域网(WAN)
  2. IP地址用于定位主机的网络地址。端口号可以标识主机中发送数据接收数据的进程(用于定位主机中的进程)。一个端口只能被一个进程绑定(通常情况),但是一个进程可以绑定多个端口号。
  3. 协议是俩个人的事情,只有双方都了解并且遵守才有意义!
  4. 协议分层,上层协议调用下层协议,下层协议给上层协议提供服务,相邻的层是可以相互交互的,但是不能跨层级。
  5. TCP/IP五层网络模型和封装,假设主机A给主机B发了个helloworld 主机A发送的过程 一.应用层   应用程序会把输入的helloworld构造成约定好的应用层协议的报文    应用程序就会把这个应用数据报文,交给传输层协议    传输层是操作系统内核实现的,操作系统提供了一些API给应用程序,    这些API叫做socket api,代码调用这些api就可以把应用层的数据交给传输层(交给了操作系统内核)二.传输层   传输层这里有很多协议,最典型的就是TCP协议,此处以TCP为例    TCP协议要在之前的基础上,加上个TCP的协议报头    这个TCP报头里面最重要的就是源端口和目的端口!    传输层继续将这个数据交给网络层进行处理         三.网络层   网络层中最典型的就是IP协议   IP协议把整个TCP数据看成整体,作为载荷部分,在前头加上IP协议报头    IP协议报头里面有很多信息,最关键的就是源IP和目的IP   构造好IP数据报之后,IP协议继续把整个数据交给数据链路层         四.数据链路层   数据链路层的协议有很多,最典型的就是以太网    以太网这个歌协议既管数据链路层,又管物理层    以太网数据帧将IP数据报的前头加上帧头(源mac地址和目的mac地址),后头加上帧尾(校验和) 五.物理层   到达物理层的数据已经组织好了    就可以通过物理层设备(网卡)把上述数据的二进制bit流转换成光信号或电信号来传输
  6. 分用就是封装的逆过程,封装是打包快递,而分用就是拆开快递。
  7. 网络中的细节太多了,如果一个协议搞定,那这个协议就会非常的复杂。因此就需要拆分,拆分的多了,又要分层。拆分之后,一个协议负责一件事情,这样才把这些关键信息放到了不同的协议报头中。

2.网络编程

  1. 网络编程指的是网络上的主机,通过不同的进程,以编程的方式实现网络通信网络编程主要是针对应用层。
  2. 网络编程套接字,就是研究如何写代码完成网络编程。socket api是一切网络编程的基础。
  3. socket套接字是操作系统给应用程序提供的API,描述的是应用层和传输层的交互其实socket api就是传输层给应用层提供的
  4. API就是一组类和方法。应用程序就可以通过socket api来进行网络编程(操作网卡)。
  5. 网络传输层中又很多种协议,最主要的就是TCP和UDP。因此操作系统就提供了俩个不同的版本的API。
  6. 传输层中TCP和UDP的区别
TCP UDP
有连接 无连接
可靠传输 不可靠传输
面向字节流 面向数据报
全双工 全双工

  1. TCP和文件操作一样是基于“流”的,而UDP则是以“数据报”为基本单位。全双工是一个通道,双向通信;半双工是一个通道,单向通信。网络通信一般都是全双工的。有连接就相当于打电话,必须通信的双方建立好了连接才可以正常打电话;而无连接相当于发短信,直接就可以发送过去。

3.UDP数据报套接字

  1. DatagramSocketDatagramPacket是UDP socket需要掌握的类。
  2. DatagramSocket,是网卡的代言人,借助这个类来读写网卡。通过网卡发送数据就是写文件,接收数据就是读文件。
方法签名 说明
DatagramSocket() 一般用于客户端,创建一个UDP数据报套接字的socket,绑定到随机一个端口
DatagramSocket(int port) 一般用于服务器,创建一个UDP数据报套接字的socket,绑定到指定端口
void receive(DatagramPacket p ) 接收数据报,没有收到会阻塞等待
void send(DatagramPacket p ) 发送数据报,不会阻塞等待
void close() 关闭数据报套接字

  1. socket本质上是一个文件。socket对应到网卡这个硬件设备,操作系统也是把网卡当作文件来管理。通过网卡发送数据,就是写文件;通过网卡接收数据,就是读文件。
  2. DatagramPacket,代表一个UDP数据包,是一次发送/接受的基本单位;发送和接收的是DatagramPacket。
方法签名 说明
DatagramPacket(byte[ ] b,int length) 构造一个DatagramPacket用来接收数据报,接收的数据保存在字节数组里
DatagramPacket(byte[ ] b,int offset,int length,address) 构造一个DatagramPacket用来发送数据报,发送的数据为字节数组的指定长度。address为指定目的主机的IP和端口号
getAddress() 从接收的数据报中获取发送端主机IP地址;或从发送的数据报中获取接收端主机IP地址
int getPort() 从接收的数据报中获取发送端主机端口号;或从发送的数据报中获取接收端主机端口号
byte[ ] getData() 获取数据报中的数据

  1. UDP实现回显服务器(服务器部分)
//UDP版本:回显服务器的服务器部分
public class UdpEchoServer {
    private DatagramSocket socket = null;
    //参数的端口表示服务器要绑定的端口
    //不需要指定IP,就是本机的IP
    public UdpEchoServer(int port) throws SocketException {
        socket = new DatagramSocket(port);
    }
    //启动服务器
    public void start() throws IOException {
        System.out.println("服务器启动了!!!");
        while(true){
            //1.读取请求并且解析
            //socket的receive操作需要一个空的requestPacket,receive方法的参数是一个输出型参数
            //将空的DatagramPacket对象交给receive,在receive里面负责把从网卡读到的数据填充到这个对象中
            DatagramPacket requestPacket = new DatagramPacket(new byte[1024],1024);//要给DatagramPacket申请内存空间
            socket.receive(requestPacket);
            //将DatagramPacket转换成字符串    getData()是获取数据报中的数据,返回一个byte[]
            String request = new String(requestPacket.getData(),0, requestPacket.getLength());
            //2.根据请求计算响应
            String response = process(request);
            //3.把响应返回给客户端
            //发送DatagramPacket对象需要指定IP地址和端口号
            DatagramPacket responsePacket = new DatagramPacket(    //getSocketAddress就是得到客户端的IP和端口号
                    response.getBytes(),response.getBytes().length, requestPacket.getSocketAddress());
            socket.send(responsePacket);
            //4.打印一个日志
            System.out.printf("[%s %d]: req: %s ; resp: %s\n",
                    requestPacket.getAddress().toString(),requestPacket.getPort(),request,response);
        }
    }
    public String process(String request) {
        return request;
    }
    public static void main(String[] args) throws IOException {
        UdpEchoServer server = new UdpEchoServer(1025);
        server.start();
    }
}
  1. UDP实现回显服务器(客户端部分)
//UDP版本:回显服务器的客户端部分
public class UdpEchoClient {
    private DatagramSocket socket = null;
    private String serverIP;
    private int serverPort;
    //服务器的IP一般不用写,就是本机的IP
    //需要传服务器的IP和服务器的端口
    public UdpEchoClient(String serverIp,int serverPort) throws SocketException {
        socket = new DatagramSocket();//不用指定参数
        this.serverIP = serverIp;
        this.serverPort = serverPort;
    }
    public void start() throws IOException {
        Scanner scanner = new Scanner(System.in);
        while(true){
            //1.从控制台上读取用户输入的内容
            System.out.print("-> ");
            String request = scanner.nextLine();
            //2.构造一个UDP请求,发送给服务器
            DatagramPacket requestPacket = new DatagramPacket(
                    //request.getBytes().length这里的length单位是字节
                    //request.length()这里的length()单位是字符,不可以改成这样
                    request.getBytes(),request.getBytes().length, InetAddress.getByName(this.serverIP),this.serverPort);
            socket.send(requestPacket);
            //3.从服务器接收响应,并且转成字符串
            DatagramPacket responsePacket = new DatagramPacket(new byte[1024],1024);
            socket.receive(responsePacket);
            String response = new String(responsePacket.getData(),0, responsePacket.getLength());
            //4.把响应显示到控制台上
            System.out.println(response);
        }
    }
    public static void main(String[] args) throws IOException {
        //IP是某某食堂,端口号是某某窗口
        UdpEchoClient client = new UdpEchoClient("127.0.0.1",1025);
        client.start();
    }
}
  1. DatagramPacket的三种构造方法
  2. 为什么服务器需要指定端口,而客户端不用指定端口???答:服务器指定端口目的就是方便客户端找到服务器在哪而客户端不指定端口因为操作系统会分配一个空闲的端口,如果手动指定了万一用户电脑上的其他程序占用了这个端口,就会导致程序无法正确运行了。
  3. 对于服务器来说,读取请求并且解析根据请求计算响应把响应写回到客户端执行的速度是极快的。如果有多个客户端同时发来请求,服务器也是可以响应的,但是本质上这三个请求的串行处理的!
  4. 当前俩个程序放在同一个主机上是通过127.0.0.1这个IP来通信的;也可以把俩个程序放在不同的主机上也是可以通信的,但是如果放在不同的主机上,要确保服务器的地址是可以访问到的!

4.TCP流套接字:

  1. ServerSocketSocket是TCP流套接字需要掌握的俩个类。
  2. ServerSocket是创建TCP服务器的api,给服务器使用的类,用来监听端口
方法签名 说明
ServerSocket(int port) 创建一个服务端流套接字Socket,并且绑定指定端口
Socket accept() 有客户端连接后,返回一个服务端Socket对象,并基于该Socket建立与客户端的连接否则阻塞等待
void close() 关闭此套接字

  1. Socket既会给服务器使用也会给客户端使用,用来传输数据。
方法签名 说明
Socket(String host,int port) 创建一个客户端流套接字Socket,并且尝试和对应IP的主机上对应端口的进程建立连接
InetAddress getInetAddress() 返回套接字所连接的地址,获取IP和端口
int getPort() 返回套接字所连接的端口
InputStream  getInputStream() 返回此套接字的输入流
OutputStream getOutputStream() 返回此套接字的输出流

  1. TCP实现回显服务器(服务器部分)
//TCP版本:回显服务器服务器部分
public class TcpEchoServer {
    private ServerSocket listenSocket = null;
    public TcpEchoServer(int port) throws IOException {
        listenSocket = new ServerSocket(port);
    }
    public void start() throws IOException {
        System.out.println("服务器启动!!");
        //使用线程池
        ExecutorService service = Executors.newCachedThreadPool();
        while(true) {
            //1.先调用accept
            Socket clientSocket = listenSocket.accept();
            //2.再来处理这个连接,这里应该使用多线程,每个客户端连上来都分配一个新的线程负责处理
            //使用多线程确实可以解决问题,但是会频繁的创建和销毁线程!
//            Thread t = new Thread(()->{
//                try {
//                    processConnection(clientSocket);
//                } catch (IOException e) {
//                    throw new RuntimeException(e);
//                }
//            });
//            t.start();
            service.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        processConnection(clientSocket);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }
    private void processConnection(Socket clientSocket) throws IOException {
        System.out.printf("[%s:%d] 客户端上线!\n",
                clientSocket.getInetAddress().toString(),clientSocket.getPort());
        //处理客户端的请求
        //clientSocket代表的是服务器的网卡,inputStream代表从网卡读数据也就相当于从客户端读取数据
        try(InputStream inputStream = clientSocket.getInputStream();
            OutputStream outputStream = clientSocket.getOutputStream()){
            while(true){
                //1.读取请求并且解析
                Scanner scanner = new Scanner(inputStream);
                if(!scanner.hasNext()){
                    System.out.printf("[%s:%d] 客户端下线!\n",
                            clientSocket.getInetAddress().toString(),clientSocket.getPort());
                    break;
                }
                String request = scanner.next();
                //2.根据请求计算响应
                String response = process(request);
                //3.把响应写回到客户端
                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(response);
                //刷新缓冲区确保数据确实是通过网卡发送出去了
                printWriter.flush();
                System.out.printf("[%s:%d] req: %s; resp: %s\n",
                        clientSocket.getInetAddress().toString(),clientSocket.getPort(),request,response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //为什么这个clientSocket要关闭文件,前面的listenSocket和UDP程序中的socket都不需要关闭文件呢?
            clientSocket.close();
        }
    }
    public String process(String request) {
        return request;
    }
    public static void main(String[] args) throws IOException {
        TcpEchoServer server = new TcpEchoServer(9090);
        server.start();
    }
}
  1. TCP实现回显服务器(客户端部分)
//TCP版本:回显服务器客户端部分
public class TcpEchoClient {
    private Socket socket = null;
    public TcpEchoClient(String serverIp, int serverPort) throws IOException {
        socket = new Socket(serverIp, serverPort);
    }
    public void start() {
        Scanner scanner = new Scanner(System.in);
        try (InputStream inputStream = socket.getInputStream();
             OutputStream outputStream = socket.getOutputStream()) {
            while (true) {
                //1.从控制台读取数据
                System.out.print("-> ");
                String request = scanner.next();
                //2.发送请求给服务器
                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(request);
                printWriter.flush();
                //3.从服务器上接收响应
                Scanner respScanner = new Scanner(inputStream);
                String response = respScanner.next();
                //4.把响应显示到界面上
                System.out.println(response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) throws IOException {
        TcpEchoClient server = new TcpEchoClient("127.0.0.1",9090);
        server.start();
    }
}
  1. TCP实现回显服务器的服务器代码部分,如果使用1的话,就不能让多个客户端同时使用服务器;如果使用2,频繁的创建和销毁代价较大,所以推荐使用线程池!
  2. TCP实现回显服务器的服务器代码中需要close文件!
  3. 启动服务器,如果没有客户端建立连接,服务器就会阻塞等待。如果有一个客户端过来了,此时就会显示客户端已上线并且向下执行代码。如果再有一个客户端也过来了,使用上述的方案1那么不会显示这个客户端已上线
  4. TCP中的长短连接。TCP发送数据时需要先建立连接,什么时候关闭连接就决定是短连接还是长连接。短连接:每次收到数据并返回响应后,都关闭连接,也就是短连接只能一次收发数据,TCP每个连接只处理一个客户端请求能够保证快速调用到accept。长连接:不关闭连接,一直保持连接状态,双方不停的收发数据,也就是长连接可以多次收发数据,TCP建立连接之后,要处理客户端的多次请求才导致无法快速调用accept。

如果对您有帮助的话,

不要忘记点赞+关注哦,蟹蟹

如果对您有帮助的话,

不要忘记点赞+关注哦,蟹蟹

如果对您有帮助的话,

不要忘记点赞+关注哦,蟹蟹

相关文章
|
2月前
|
机器学习/深度学习 PyTorch TensorFlow
卷积神经网络深度解析:从基础原理到实战应用的完整指南
蒋星熠Jaxonic,深度学习探索者。深耕TensorFlow与PyTorch,分享框架对比、性能优化与实战经验,助力技术进阶。
|
2月前
|
监控 负载均衡 安全
WebSocket网络编程深度实践:从协议原理到生产级应用
蒋星熠Jaxonic,技术宇宙中的星际旅人,以代码为舟、算法为帆,探索实时通信的无限可能。本文深入解析WebSocket协议原理、工程实践与架构设计,涵盖握手机制、心跳保活、集群部署、安全防护等核心内容,结合代码示例与架构图,助你构建稳定高效的实时应用,在二进制星河中谱写极客诗篇。
WebSocket网络编程深度实践:从协议原理到生产级应用
|
8月前
|
机器学习/深度学习 存储 算法
NoProp:无需反向传播,基于去噪原理的非全局梯度传播神经网络训练,可大幅降低内存消耗
反向传播算法虽是深度学习基石,但面临内存消耗大和并行扩展受限的问题。近期,牛津大学等机构提出NoProp方法,通过扩散模型概念,将训练重塑为分层去噪任务,无需全局前向或反向传播。NoProp包含三种变体(DT、CT、FM),具备低内存占用与高效训练优势,在CIFAR-10等数据集上达到与传统方法相当的性能。其层间解耦特性支持分布式并行训练,为无梯度深度学习提供了新方向。
305 1
NoProp:无需反向传播,基于去噪原理的非全局梯度传播神经网络训练,可大幅降低内存消耗
|
3月前
|
机器学习/深度学习 人工智能 算法
卷积神经网络深度解析:从基础原理到实战应用的完整指南
蒋星熠Jaxonic带你深入卷积神经网络(CNN)核心技术,从生物启发到数学原理,详解ResNet、注意力机制与模型优化,探索视觉智能的演进之路。
401 11
|
3月前
|
机器学习/深度学习 算法 搜索推荐
从零开始构建图注意力网络:GAT算法原理与数值实现详解
本文详细解析了图注意力网络(GAT)的算法原理和实现过程。GAT通过引入注意力机制解决了图卷积网络(GCN)中所有邻居节点贡献相等的局限性,让模型能够自动学习不同邻居的重要性权重。
484 0
从零开始构建图注意力网络:GAT算法原理与数值实现详解
|
3月前
|
安全 测试技术 虚拟化
VMware-三种网络模式原理
本文介绍了虚拟机三种常见网络模式(桥接模式、NAT模式、仅主机模式)的工作原理与适用场景。桥接模式让虚拟机如同独立设备接入局域网;NAT模式共享主机IP,适合大多数WiFi环境;仅主机模式则构建封闭的内部网络,适用于测试环境。内容简明易懂,便于理解不同模式的优缺点与应用场景。
403 0
|
5月前
|
机器学习/深度学习 人工智能 PyTorch
零基础入门CNN:聚AI卷积神经网络核心原理与工业级实战指南
卷积神经网络(CNN)通过局部感知和权值共享两大特性,成为计算机视觉的核心技术。本文详解CNN的卷积操作、架构设计、超参数调优及感受野计算,结合代码示例展示其在图像分类、目标检测等领域的应用价值。
293 7
|
7月前
|
监控 应用服务中间件 Linux
掌握并发模型:深度揭露网络IO复用并发模型的原理。
总结,网络 I/O 复用并发模型通过实现非阻塞 I/O、引入 I/O 复用技术如 select、poll 和 epoll,以及采用 Reactor 模式等技巧,为多任务并发提供了有效的解决方案。这样的模型有效提高了系统资源利用率,以及保证了并发任务的高效执行。在现实中,这种模型在许多网络应用程序和分布式系统中都取得了很好的应用成果。
214 35
|
7月前
|
机器学习/深度学习 算法 测试技术
图神经网络在信息检索重排序中的应用:原理、架构与Python代码解析
本文探讨了基于图的重排序方法在信息检索领域的应用与前景。传统两阶段检索架构中,初始检索速度快但结果可能含噪声,重排序阶段通过强大语言模型提升精度,但仍面临复杂需求挑战
232 0
图神经网络在信息检索重排序中的应用:原理、架构与Python代码解析
|
6月前
|
安全 Java 程序员
分析Muduo网络库源码中的TcpServer组件工作原理
简言之,TcpServer 在 Muduo 中的角色,就是一位终极交通指挥员,它利用现代计算机网络的魔法,确保数据如同车辆一般,在信息高速公路上自由、安全、高效地流动。
82 0