Socket 通信机制详解

Socket 是网络编程中一种重要的通信机制,它允许不同的计算机通过网络进行数据交换。

一、 Socket 的概念

Socket(套接字)是计算机网络编程中的一种抽象,它提供了在网络上进行通信的接口。

Socket 本质上是一种通信的端点,它在网络上标识了一个通信链路的两端,并提供了通信双方所需的接口和功能。

通过使用 Socket,可以在不同计算机之间建立连接,并进行数据的传输和交换(网络通信)

二、 Socket 类型

在 Socket 编程中,常见的两种类型是 TCP Socket 和 UDP Socket。

  • TCP Socket:TCP(传输控制协议)是一种面向连接的协议,它提供可靠的、有序的数据传输。TCP Socket 基于 TCP 协议,使用三次握手建立连接,确保数据的可靠性和顺序性。

  • UDP Socket:UDP(用户数据报协议)是一种无连接的协议,它提供了简单的数据传输服务,但不保证数据的可靠性和顺序性。UDP Socket 基于 UDP 协议,无需建立连接,适用于一些实时性要求高、允许一定数据丢失的应用场景。

三、 Socket 的工作原理

3.1 三次握手

这里需要先讲一下TCP 协议中的三次握手。

同步序号:SYN   确认字段:ACK  随机数据:seq

规定:

当SYN=1,ACK=0表示连接请求

当SYN=1,ACK=1表示同意建立连接

如上图,纵向的轴,是一个时间轴。

第一次握手:时间点1,客户端向服务端发送连接请求报文段。ACK=0,SYN=1,seq=x

将SYN位置为1,Sequence Number为x;然后,客户端进入SYN_SEND状态,等待服务器的确认;

第二次握手:服务器收到SYN报文段。服务器收到客户端的SYN报文段,需要对这个SYN报文段进行确认,设置Acknowledgment Number为x+1(Sequence Number+1);同时,自己自己还要发送SYN请求信息,将SYN位置为1,Sequence Number为y;服务器端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时服务器进入SYN_RECV状态;

第三次握手:客户端收到服务器的SYN+ACK报文段。然后将Acknowledgment Number设置为y+1,向服务器发送ACK报文段,这个报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。

完成了三次握手,客户端和服务器端就可以开始传送数据。


TCP/IP 三次握手:

TCP/IP 三次握手_tcp三次握手-CSDN博客

创建 Socket与TCP/IP 三次握手有什么关系:

在 TCP 协议中,建立连接通常需要进行三次握手,而创建 Socket 对象通常是在握手之前的准备工作之一用于准备建立连接所需的资源和信息。(创建一个套接字,收集一些计算机的资源,将一些资源绑定套接字里面,以及接受和发送数据的函数等等,这些功能接口在一起构成了socket的编程。)

具体来说,在客户端发起连接之前,通常会创建一个 Socket 对象,然后调用 connect 方法来发起连接请求;

而在服务器端接受连接之前,通常会创建一个 Socket 对象,然后调用 accept 方法来接受连接请求并返回一个新的 Socket 对象,用于与客户端进行通信。

3.2  Socket 的工作原理

当客户端和服务端使用 Socket 进行通信时,它们的工作原理有所不同。

3.2.1 客户端的 Socket 工作原理

  1. 创建 Socket 对象:客户端首先会创建一个 Socket 对象,用于与服务器端建立连接。

  2. 连接服务器:客户端通过调用 Socket 对象的 connect 方法来连接服务器。在连接过程中,客户端会发送连接请求给服务器端。

  3. 发送数据:一旦连接建立成功,客户端就可以通过 Socket 对象的 send 方法向服务器端发送数据。发送的数据通常包括请求信息、参数等。

  4. 接收数据:客户端通过 Socket 对象的 recv 方法来接收服务器端发送的响应数据。客户端会等待服务器端的响应,并在接收到响应后进行相应的处理。

  5. 关闭连接:通信结束后,客户端会调用 Socket 对象的 close 方法来关闭连接,并释放资源。

3.2.2 服务端的 Socket 工作原理

  1. 创建 Socket 对象:服务器端首先会创建一个 Socket 对象,用于监听客户端的连接请求。

  2. 绑定地址和端口:服务器端会将 Socket 对象绑定到一个特定的地址和端口上,以便客户端能够连接到该地址和端口。

  3. 监听连接:服务器端通过调用 Socket 对象的 listen 方法来开始监听客户端的连接请求。一旦调用了 listen 方法,服务器就处于等待客户端连接的状态。

  4. 接受连接:当客户端发起连接请求时,服务器端会调用 accept 方法来接受连接。在接受连接之后,服务器端会创建一个新的 Socket 对象,用于与该客户端进行通信。

  5. 接收和处理数据:一旦连接建立成功,服务器端就可以通过新创建的 Socket 对象来接收客户端发送的数据,并进行相应的处理。服务器端会等待客户端发送数据,并在接收到数据后进行解析和处理。

  6. 发送数据:服务器端也可以通过 Socket 对象的 send 方法向客户端发送数据。这通常发生在服务器端需要向客户端发送响应或其他信息时。

  7. 关闭连接:通信结束后,服务器端会调用 Socket 对象的 close 方法来关闭连接,并释放资源。

总的来说,客户端和服务端的 Socket 工作原理都涉及创建 Socket 对象、建立连接、发送和接收数据以及关闭连接等步骤,但具体的操作和流程略有不同。客户端主要负责发起连接和发送请求,而服务端主要负责监听连接、接受连接和处理请求。

四、代码

4.1 Java代码

4.1.1 客户端代码WebClient

import java.io.*;
import java.net.*;
import java.util.Scanner;

public class WebClient {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String messageA; // 储存A发送的消息
        try {
            // 创建 Socket,连接到服务器的 IP 地址和端口
            Socket socket = new Socket("127.0.0.1", 8888);

            // 获取输入流和输出流
            InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream();

            while (true) {  // 一直保持发送
                System.out.print("输入消息:" + '\t');
                // 输入消息
                messageA = scanner.nextLine();
                // 发送消息给服务器
                outputStream.write(messageA.getBytes());
                outputStream.flush(); // 刷新缓冲区,确保消息发送给服务器

                // 接收服务器的响应
                byte[] buffer = new byte[1024];
                int length = inputStream.read(buffer);
                String response = new String(buffer, 0, length);
                System.out.println("B: " + response);
            }

            // 关闭连接
//            outputStream.close();
//            inputStream.close();
//            socket.close();

        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }
}

4.1.2 客户端代码WebServer

import java.io.*;
import java.net.*;
import java.util.Scanner;

public class WebServer {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String messageB = ""; // 储存B发送的消息
        try {
            // 创建 ServerSocket,监听指定的端口
            ServerSocket serverSocket = new ServerSocket(8888);

            System.out.println("服务启动,等待客户端连接... ");

            // 等待客户端连接
            Socket socket = serverSocket.accept();

            // 获取输入流和输出流
            InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream();

            while (true) {
                // 接收客户端发送的数据
                byte[] buffer = new byte[1024];
                int length = inputStream.read(buffer);
                String message = new String(buffer, 0, length);
                System.out.println("A: " + message);

                System.out.print("输入消息:" + '\t');
                messageB = scanner.nextLine();
                // 发送响应给客户端
                outputStream.write(messageB.getBytes());
                outputStream.flush(); // 刷新缓冲区,确保消息发送给客户端
            }

            // 关闭连接
//            outputStream.close();
//            inputStream.close();
//            socket.close();
//            serverSocket.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

运行结果:

这样我们就实现了基于 TCP 协议的长连接。

TCP(传输控制协议)是一种可靠的、面向连接的协议,它提供了数据传输的可靠性和顺序性。在 TCP 长连接中,客户端和服务器之间建立一次连接后,可以持续地在该连接上进行数据传输,直到其中一方显式地关闭连接为止。TCP 长连接适合于需要保持持续通信的场景,例如即时通讯、远程控制等。

既然tcp协议的长连接就能实现续通信的场景,为什么还要用web Socket 呢?

尽管 TCP 协议的长连接可以实现持续通信的场景,但 WebSocket 协议在某些情况下更适合。

  1. 更轻量级的通信开销: WebSocket 协议相比于 HTTP 协议(即基于长连接的 HTTP 长轮询或者服务器推送技术)具有更轻量级的通信开销。WebSocket 在建立连接后,在客户端和服务器之间建立了全双工的通信通道,通过一个简单的握手过程后,数据可以在客户端和服务器之间进行双向实时通信,无需每次都携带 HTTP 的头部信息,减少了通信的开销。

  2. 更低的延迟: WebSocket 协议通过在客户端和服务器之间建立长期的双向通信通道,可以实现实时的双向通信,从而降低了通信的延迟。对于需要实时性较高的应用场景,如在线游戏、实时聊天等,WebSocket 可以提供更好的用户体验。

  3. 更方便的API: WebSocket 提供了更简洁、方便的 API,使得开发者可以更容易地实现实时通信功能。客户端和服务器端都可以使用相同的编程模型来处理 WebSocket 连接,简化了开发流程。

  4. 更好的跨域支持: WebSocket 协议在跨域通信方面具有更好的支持,因为 WebSocket 握手过程中的 HTTP 头部信息可以包含跨域资源共享(CORS)的相关信息,使得跨域通信更加方便。

4.2 pyhton代码

4.2.1 服务端代码

# -*- coding:utf-8 -*-
# @Author: 喵酱
# @time: 2024 - 04 -10
# @File: server.py
# desc:
import socket

def main():
    # 创建套接字
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 绑定IP地址和端口
    server_socket.bind(('localhost', 8888))
    # 监听连接
    server_socket.listen(1)

    print("服务启动,等待客户端连接... ")

    # 接受客户端连接
    client_socket, client_address = server_socket.accept()
    print(f"客户端 {client_address} 已连接")

    while True:
        try:
            # 接收客户端消息
            message = client_socket.recv(1024).decode()
            print("A:", message)

            # 发送消息给客户端
            message_b = input("输入消息:")
            client_socket.send(message_b.encode())
        except Exception as e:
            print("发生异常:", e)
            break

    # 关闭连接
    client_socket.close()
    server_socket.close()

if __name__ == "__main__":
    main()

4.2.2 客户端代码

# -*- coding:utf-8 -*-
# @Author: 喵酱
# @time: 2024 - 04 -10
# @File: client.py
# desc:
import socket

def main():
    # 创建套接字
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 连接服务器
    client_socket.connect(('localhost', 8888))

    while True:
        try:
            # 发送消息给服务器
            message_a = input("输入消息:")
            client_socket.send(message_a.encode())

            # 接收服务器响应
            response = client_socket.recv(1024).decode()
            print("B:", response)
        except Exception as e:
            print("发生异常:", e)
            break

    # 关闭连接
    client_socket.close()

if __name__ == "__main__":
    main()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/541196.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于springboot+vue实现的药品信息管理系统

作者主页:Java码库 主营内容:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】:Java 【框架】:spring…

java算法day52 | 动态规划part13 ● 300.最长递增子序列 ● 674. 最长连续递增序列 ● 718. 最长重复子数组

300.最长递增子序列 思路: 子序列问题是动态规划解决的经典问题,当前下标i的递增子序列长度,其实和i之前的下表j的子序列长度有关系,那又是什么样的关系呢。 接下来,我们依然用动规五部曲来详细分析一波: …

R:普通分组柱状图

输入文件实例&#xff08;存为csv格式&#xff09; library(ggplot2) library(ggbreak)# 从CSV文件中读取数据 setwd("C:/Users/fordata/Desktop/研究生/第二个想法(16s肠型&#xff0b;宏基因组功能)/第二篇病毒组/result/otherDB") data <- read.csv("feta…

elementui中el-select下拉列表偏移问题

问题截图 解决方法 在el-select中添加:popper-append-to-body"false"即可 加完后的效果

【MATLAB源码-第48期】基于matlab的16QAM信号盲解调仿真。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 16QAM (16个象限幅度调制) 是一种广泛使用的数字调制技术。在无线和有线通信系统中&#xff0c;为了在固定的带宽内发送更多的信息&#xff0c;高阶调制如16QAM被使用。下面是16QAM盲解调的基本步骤、优缺点及应用场景。 16…

Spring Boot 学习(5)——开发流程:快速入门

花了几天的时间&#xff0c;整出个 “hello spring boot”&#xff0c;并且把它从 2 搞到了 3。 纸上得来终觉浅&#xff01;自己实践出真知&#xff01;现在再回头来囫囵一遍&#xff0c;加深下印象。回想下从前自觉某一编程语言大都如此&#xff0c;先找到简单示例照着画一遍…

【音视频流媒体服务端开发学习指南】音视频驱动、多媒体中间件、流媒体服务器的开发,开发过即时通讯+音视频通话的大型项目

音视频流媒体开发是一个涉及多种技术和知识领域的实践领域。以下是一份指南&#xff0c;帮助你系统学习流媒体开发&#xff1a; 理解基础概念&#xff1a; 习关于音视频数据的基础知识&#xff0c;包括常见的音频与视频格式、编解码器(codec)、容器格式等。 了解流媒体的基本工…

操作系统(第四周 第二堂)

目录 回顾 进程运行 进程的创建 进程的工作 举例 进程的删除 举例1&#xff08;走到return 0结束&#xff09; 举例2&#xff08;利用exit&#xff08;1&#xff09;结束&#xff09; 进程通信 共享内存 生产者算法 消费者算法 消息传递 定义 算法实现 总结 回顾…

【Python习题】若一个正整数的逆序数和它自身相等,则该整数称为回文数。编写程序,找出 1000以内的所有回文数。

题干 若一个正整数的逆序数和它自身相等,则该整数称为回文数。编写程序,找出 1000以内的所有回文数。 代码

深度学习可视化模型

文章目录 CAM&#xff08; https://arxiv.org/abs/1512.04150&#xff09;算法原理 Grad-CAM(梯度加权类激活映射)算法原理 Grad-CAMScoreCAMLayerCAM 目前深度学习网络的可视化可以分为&#xff1a; 可视化卷积核。可视化特征图。可视化激活热力图&#xff0c;也就是不同位置像…

【JAVASE】带你了解String类的常用方法和常见操作

✅作者简介&#xff1a;大家好&#xff0c;我是橘橙黄又青&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a; 再无B&#xff5e;U&#xff5e;G-CSDN博客 目标&#xff1a; 1. 认识 String 类 2. 了解 String 类的基…

Flutter中间镂空的二维码扫描控件

1、UI效果图&#xff1a; 2、中间镂空UI&#xff1a; class CenterTransparentMask extends CustomClipper<Path> {final double? width;CenterTransparentMask({this.width});overridePath getClip(Size size) {final path Path()..addRect(Rect.fromLTWH(0, 0, size…

Go语言中如何正确使用 errgroup

不管是哪种编程语言,重新发明轮子都不是一个好主意。代码库重新实现如何启动多个goroutine并汇总错误也很常见。但是Go生态系统中的一个包旨在支持这种常见的用例。让我们来看看这个包并了解为什么它应该成为Go开发人员工具集的一部分。 golang.org/x是一个为标准库提供扩展的…

树上启发式合并(dsu on tree)学习

声明&#xff1a;本文部分内容摘自OI Wiki网站。详情可自行查看学习。 洛谷 P9233 题目实际上是蓝桥杯 2023 年 A 组省赛的一道题。题干大致的意思是&#xff0c;给定一个含有 n n n 个结点&#xff0c;并且以 1 1 1 为根的一棵树&#xff0c;每个节点 i i i 都有一个颜色 …

Spring框架第一篇(Spring概述与IOC思想)

文章目录 一、Spring概述二、Spring家族三、Spring Framework四、IOC思想五、IOC容器在Spring中的实现 一、Spring概述 Spring 是最受欢迎的企业级 Java 应用程序开发框架&#xff0c;数以百万的来自世界各地的开发人员使用 Spring 框架来创建性能好、易于测试、可重用的代码。…

Harbor私有镜像仓库

Docker私有仓库Harbor ​ 前面学习了Docker及Dockerfile构建镜像&#xff0c;那么构建的镜像放在哪里才能被Docker容器快速获取到呢&#xff1f;我们知道&#xff0c;可以把镜像放入Docker Hub镜像仓库&#xff0c;但是Docker Hub是国外网站&#xff0c;一方面镜像放在Docker …

童年女神大盘点:谁是第一个让你心动的动漫女神?

每当提起我们的童年记忆&#xff0c;总有一抹亮丽的色彩来自于那些国产动漫中的女性角色&#xff0c;她们以其独特的魅力、鲜明的性格和卓越的才智&#xff0c;深深地烙印在了我们的心底&#xff0c;成为了一代人的集体回忆。今天&#xff0c;让我们一同回首&#xff0c;盘点那…

napi系列学习进阶篇——NAPI异步调用

简介 OpenHarmony Napi 标准系统异步接口实现支持Callback方式和Promise方式。标准系统异步接口实现规范要求&#xff0c;若引擎开启Promise特性支持&#xff0c;则异步方法必须同时支持Callback方式和Promise方式。使用哪种方式由应用开发者决定&#xff0c;通过是否传递Call…

全新4.0版本圈子社交论坛系统 ,可打包小程序,于TP6+uni-app 全开源 可打包小程序app uniapp前端+全开源+独立版

简述 首先 圈子系统的核心是基于共同的兴趣或爱好将用户聚集在一起&#xff0c;这种设计使得用户能够迅速找到与自己有共同话题和兴趣的人。 其次 圈子系统提供了丰富的社交功能&#xff0c;如发帖、建圈子、发活动等&#xff0c;并且支持小程序授权登录、H5和APP等多种形式…

R语言记录过程

如何使用这个函数as.peakData 函数构造过程 出现问题是缺少函数的问题 up不告诉我&#xff0c;这里是代表c,h,o的值&#xff0c;你从里面获取把值&#xff0c;设置成c,h,o就可以了 现在开始测试参数 第一次 startRow : 开始查找数据的第一行。不管startRow的值是多少&#xff…