Linux网络编程:套接字编程

1.Socket套接字编程

1.1.什么是socket套接字编程

Socket套接字编程 是一种基于网络层和传输层网络通信方式,它允许不同主机上的应用程序之间进行双向的数据通信。Socket是网络通信的基本构件,它提供了不同主机间的进程间通信端点的抽象。一个Socket就是一个通信端点,它提供了应用程序访问网络通信协议(如TCP/IP)的接口。并且Socket编程基于客户端(Client)和服务器端(Server)进行全双工通信!!!

  • 客户端:通常指的是发起连接请求的一方,它使用Socket API创建一个Socket对象,并指定要连接的服务器地址和端口号,然后向服务器发送连接请求。连接建立后,客户端就可以通过Socket发送和接收数据了。
  • 服务器端:则是监听来自客户端的连接请求的一方。服务器端也使用Socket API创建一个Socket对象,并绑定到一个指定的地址和端口号上,然后开始监听来自客户端的连接请求。当有客户端连接时,服务器端会接受这个连接,并创建一个新的Socket对象来与这个客户端进行通信。

简单来说,Socket编程就是使用Socket API(应用程序接口)来编写网络应用程序。这些网络应用程序可以是客户端,也可以是服务器端,它们通过Socket进行数据的发送和接收。 

1.2.如何进行socket套接字编程

首先socket套接字编程是基于TCP、IP四层网络协议栈实现的,而在传输层协议中UDP协议是无连接、面向数据报的,TCP协议是有链接、面向字节流的,因此系统维护了两套Socket套接字编程接口,给UDP场景和TCP场景使用!!!

1.2.1.UDP的套接字编程

// UDP服务器
{int port;                                     // 服务器开放的端口号int sock_fd = socket(AF_INET, SOCK_DGRAM, 0); // 网络通信,UDP套接字// 填充sockaddr结构体对象struct sockaddr_in local;bzero(&local, sizeof(local)); // 初始化结构体local.sin_family = AF_INET;         // 绑定网络通信local.sin_port = htons();           // 绑定端口local.sin_addr.s_addr = INADDR_ANY; // 允许所有外来ip访问// 绑定指定网络信息和指定的文件系统int n = ::bind(sock_fd, (struct sockaddr *)&local, sizeof(local));// 获取客户端信息char buff_r[1024];sockaddr_in peer;socklen_t len = sizeof(peer);ssize_t n = recvfrom(sock_fd, buff_r, sizeof(buff_r) - 1, 0, (struct sockaddr *)&peer, &len);// 给客户端发送信息std::string buffer;ssize_t m = sendto(sock_fd, buffer.c_str(), buffer.size(), 0, (struct sockaddr *)&peer, &len);
}

服务器进行套接字编程流程:

  1. 通过socket函数获取套接字,其中SOCK_DGRAM对应UDP协议
  2. 构建一个sockaddr_in对象,并绑定端口和设置允许任意的IP地址访问服务器
  3. 接着通过bind函数显性绑定套接字和sockaddr_in对象
  4. 接下来就可以和客户端进行IO通信了!!! 
/ UDP客户端
{int port_server;                              // 链接服务器的端口号int ip_server;                                // 链接服务器的端口号int sock_fd = socket(AF_INET, SOCK_DGRAM, 0); // 网络通信,UDP套接字struct sockaddr_in server;bzero(&server, sizeof(server));                        // 初始化结构体server.sin_family = AF_INET;                           // 设置为网络协议server.sin_port = htons(port_server);                  // 绑定服务器端口server.sin_addr.s_addr = inet_addr(ip_server.c_str()); // 实现ip的动态绑定// 客户端不用通过bind函数显性绑定套接字// 因为服务器先启动,已经获得了套接字,只要绑定服务器的ip和端口就能使用这个套接字// 向服务器发送信息std::string buffer;ssize_t n = sendto(sock_fd, buffer.c_str(), buffer.size(), 0, (struct sockaddr *)&server, sizeof(server));// 从服务端获取信息char buff_r[1024];struct sockaddr_in client;socklen_t len = sizeof(client);ssize_t m = recvfrom(sock_fd, buff_r, sizeof(buff_r) - 1, 0, (struct sockaddr *)&client, &len);
}

 客户端进行套接字编程的流程:

  1. 通过socket函数获取套接字,其中SOCK_DGRAM对应UDP协议
  2. 绑定服务器端口和服务器ip地址
  3. 直接进行和服务器的IO通信

服务端和客户端Socket编程的异同 

  • 相同的是:都需要调用socket函数来获取套接字,设置网络协议为AF_INET和SOCK_DGRAM,并且需要设置sockaddr_in结构体,初始化这个结构体的内置变量。均共用一套IO的接口sendto和recvfrom。
  • 不同的是:服务端的IP地址设置为INADDR_ANY,表示可以绑定多个IP地址,这也符合服务器需要和多台客户端进行IO的特性。另外服务端需要显性地绑定socket_fd(套接字文件描述符)和sockaddr_in(IPV4套接字结构)。而客户端需要绑定唯一一个服务器的IP,并且不需要显性的绑定socket_fd和sockaddr_in。

1.2.2.TCP套接字编程

TCP协议是面向连接的,所以与UDP套接字流程相比,除了绑定套接字,TCP需要在通信之前先建立连接,具体来说就是:服务器监听客户端发出链接请求请求,接着客户端发出connect请求,最终服务器接收请求,获取一个通信的套接字,最终完成链接的建立。接着再进行IO通信!!!

// TCP服务器
{// 创建监听套接字int listen_sock = socket(AF_INET, SOCK_STREAM, 0);// 定义并配置本地struct sockaddr_in local;bzero(&local, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(_port);local.sin_addr.s_addr = INADDR_ANY;int n = ::bind(listen_sock, (struct sockaddr *)&local, sizeof(local));// TCP是面向连接的,需要监听client的链接int m = listen(listen_sock, 5); // 对listen这个套接字进行监听是否完成链接,设置全连接队列为5// 获取连接struct sockaddr_in peer;socklen_t len = sizeof(peer);// accept返回的新的套接字(通信套接字)int sock_fd = accept(_listen_sock, (struct sockaddr *)&peer, &len); // 用于数据通信,accept未接收会阻塞(未完成通信)!!// 通过read、write函数进行IO通信std::string buffer;ssize_t m = write(sock_fd, buffer.c_str(), buffer.size());char buffer_read[1024];ssize_t n = read(sock_fd, buffer_read, sizeof(buffer_read));
}

TCP服务端套接字编程的流程:

  1. 创建监听的套接字,然后设置协议为AF_INET和SOCK_STREAM(TCP专用)
  2. 定义并配置套接字结构体,最后进行监听套接字和网络套接字的结构体绑定
  3. 进行监听(在此期间等待客户端的connect请求)
  4. 设置网络套接字来接收客户端的信息,并通过accept函数获取到新的通信套接字
  5. 进行通信IO
// TCP客户端
{// 创建套接字int sock_fd = socket(AF_INET, SOCK_STREAM, 0);// 绑定服务器struct sockaddr_in server;server.sin_family = AF_INET;server.sin_port = htons(server_port);inet_pton(AF_INET, server_ip.c_str(), &server.sin_addr);// TCP链接服务器int n = connect(sock_fd, (struct sockaddr *)&server, sizeof(server));// 通过read、write函数进行IO通信std::string buffer;ssize_t m = write(sock_fd, buffer.c_str(), buffer.size());char buffer_read[1024];ssize_t n = read(sock_fd, buffer_read, sizeof(buffer_read));
}

TCP客户端套接字编程流程:

  1. 创建套接字,并将网络套接字结构体绑定到服务器
  2. 调用connect发起链接服务器的请求(此时处于服务端监听状态)
  3. 完成链接,进行IO通信

 到了这里,我们已经知道如何用代码来构建UDP、TCP通信最基本的架构了,而TCP是面向连接的,这也体现在listen、connect、accept这三个函数中(跟三次握手紧密相关,但不等同)。

 如图为TCP中服务端和客户端建立通信的过程。

2.理解Socket套接字编程结构

我们在1.2中学习了如何搭建Socket套接字编程的结构,但是我们还不知道什么是Socket、什么是sockaddr_in和为什么要将sockaddr_in类型强转为(struct sockaddr*)等等,所以在有了对Socket编程的使用理解的基础上,我们来讲一下原理!!!

2.1.网络字节序

我们知道主机的地址排布,也就是字节序是可能存在不同的,大端机的字节序排列为高地址,小端机的字节序排列为低地址,那么这样就会导致在网络通信时,字节序读取不一致导致数据不一致问题。

例如在大端机中,32位整数,0x12345678,地址排布为:78563412,小端机则表示为:12345678

所以为了统一字节序的读取,在套接字编程中需要对网络字节序进行规定,以大端字节序为网络字节序标准,进行读取。我们在回到我们的代码中:

local.sin_port = htons(port);    // htons即为字节序转换函数 

而这些htons函数为系统提供的转换字节序的接口函数!

#include <arpa/inet.h>//必须包含的头文件
// 主机序列转网络序列
uint32_t htonl(uint32_t hostlong);//将主机上unsigned int类型的数据转换成对应网络字节序
uint16_t htons(uint16_t hostshort);//将主机上unsigned short类型的数据转换成对应网络字节序
// 网络序列转主机序列
uint32_t ntohl(uint32_t netlong);//将从网络中读取的unsigned int类型的数据转换成当前计算机字节序
uint16_t ntohs(uint16_t netshort);//将从网络中读取的unsigned short类型的数据转换成当前计算机字节序

 所以当我们在网络中获取了一些字节序数据,我们需要对他进行大端字节序的转换成符合本机的字节序列。

这里即为将网络获取的数据字节序转化为本机的数据字节序,而htons即为将本机的字节序数据转化为网络字节序(大端) 

2.2.网络套接字结构体

我们之前在1.2.提及了一个新名称“网络套接字结构体”,而这个结构体用于标识网络通信的端点,包括IP地址、端口号和地址族等信息。

// 通用网络套接字结构
struct sockaddr
{__SOCKADDR_COMMON(sa_); /* Common data: address family and length.  */char sa_data[14];       /* Address data.  */
};// 网络套接字结构
struct sockaddr_in
{__SOCKADDR_COMMON(sin_);in_port_t sin_port;      /* Port number.  */struct in_addr sin_addr; /* Internet address.  *//* Pad to size of `struct sockaddr'.  */unsigned char sin_zero[sizeof(struct sockaddr) -__SOCKADDR_COMMON_SIZE -sizeof(in_port_t) -sizeof(struct in_addr)];
};

如图:我们在网络进行IO通信时,就是传输这个通用结构体对象sockaddr,所以我们在1.2.中的代码中也经常看到类型转换为(struct sockaddr *)。而这里也可以看作是C语言实现的多态,其中sockaddr为基类、sockaddr_in和sockaddr_un为派生类。

3.文件+socket+系统+网络

66-2小时33分

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

免费开源的后端API服务-supabase安装和使用-简直是前端学习者福音

文章目录 它是什么安装和部署关于安装关于部署1、注册用户2、创建组织3、创建项目 创建数据库表&#xff08;填充内容&#xff09;填充数据库表 使用postman联调API 它是什么 一个开源免费的后端框架&#xff0c;firebase的替代品。可以简单理解类似于headless cms&#xff0c…

浅谈定时器之泊松随机定时器

浅谈定时器之泊松随机定时器 “泊松随机定时器”(Poisson Random Timer)&#xff0c;它允许你基于泊松分布来随机化请求之间的延迟时间&#xff0c;这对于模拟具有随机到达率的事件特别有用&#xff0c;如用户访问网站或服务的请求。 泊松分布简介 泊松分布是一种统计与概率…

HarmonyOS开发探索:父子组件手势绑定问题处理

场景一&#xff1a;父子组件同时绑定手势的冲突处理 效果图 方案 在默认情况下&#xff0c;手势事件为非冒泡事件&#xff0c;当父子组件绑定相同的手势时&#xff0c;父子组件绑定的手势事件会发生竞争&#xff0c;最多只有一个组件的手势事件能够获得响应&#xff0c;默认子…

有哪些方法可以恢复ios15不小心删除的照片?

ios15怎么恢复删除的照片&#xff1f;在手机相册里意外删除了重要的照片&#xff1f;别担心&#xff01;本文将为你介绍如何在iOS 15系统中恢复已删除的照片。无需专业知识&#xff0c;只需要按照以下步骤操作&#xff0c;你就能轻松找回宝贵的回忆。 一、从iCloud云端恢复删除…

Transformer动画讲解 - 工作原理

Transformer模型在多模态数据处理中扮演着重要角色,其能够高效、准确地处理包含不同类型(如图像、文本、音频、视频等)的多模态数据。 Transformer工作原理四部曲:Embedding(向量化)、Attention(注意力机制)、MLPs(多层感知机)和Unembedding(模型输出)。 阶段一:…

网上下载的PDF文件为何不能复制文字?该怎么办呢?

不知道大家有没有到过这种情况&#xff1f;在网上下载的PDF文件打开之后&#xff0c;发现选中文字之后无法复制。甚至其他功能也都无法使用&#xff0c;这是怎么回事&#xff1f;该怎么办&#xff1f; 首先&#xff0c;有可能PDF文件是扫描文件&#xff0c;是扫描文件的话&…

Gradle学习-4 创建二进制插件工程

二进制插件工程创建有两种方式&#xff1a; 创建独立的工程&#xff0c;调试的时候&#xff0c;需要手动发布成一个二进制插件jar包&#xff0c;给其他工程里面引用&#xff0c;进行功能测试。这种方式是比较麻烦的。创建buildSrc子工程&#xff0c;它是一个大工程中的子工程&…

云计算【第一阶段(19)】磁盘管理与文件系统 LVM与磁盘配额(二)

目录 一、LVM概述 1.1、LVM机制的基本概念 ​编辑 1.2、LVM的管理命令 1.3、lvm存储 两种机制 1.4、lvm应用实例 二、磁盘配额概述 2.1、设置磁盘配额 2.2.1、实现磁盘限额的条件 2.2.2、linux磁盘限额的特点 2.2.3、磁盘配额管理 一、LVM概述 1.1、LVM机制的基本概…

大模型ReAct:思考与工具协同完成复杂任务推理

ReAct: Synergizing Reasoning and Acting in Language Models Github&#xff1a;https://github.com/ysymyth/ReAct 一、动机 人类的认知通常具备一定的自我调节&#xff08;self-regulation&#xff09;和策略制定&#xff08;strategization&#xff09;的能力&#xff0…

Java案例抢红包

目录 一&#xff1a;题目要求&#xff1a; 二&#xff1a;思路分析&#xff1a;&#xff08;遇见问题先想出完整的思路逻辑再去动手事半功倍&#xff09; 三&#xff1a;具体代码&#xff1a; 一&#xff1a;题目要求&#xff1a; 二&#xff1a;思路分析&#xff1a;&#x…

武汉星起航:跨境电商流量红利爆发,2023年出海企业迎突破增长

在数字时代的浪潮中&#xff0c;中国跨境电商以惊人的爆发力崭露头角&#xff0c;成为全球贸易的璀璨新星。2023年数据显示&#xff0c;跨境电商出口额高达1.83万亿元&#xff0c;同比增长19.6%&#xff0c;这一显著增速不仅刷新纪录&#xff0c;更为众多出海企业带来了前所未有…

【RabbitMQ问题踩坑】RabbitMQ设置手动ack后,消息队列有多条消息,只能消费一条,就不继续消费了,这是为什么 ?

现象&#xff1a;我发送5条消息到MQ队列中&#xff0c;同时&#xff0c;我在yml中设置的是需要在代码中手动确认&#xff0c;但是我把代码中的手动ack给关闭了&#xff0c;会出现什么情况&#xff1f; yml中配置&#xff0c;配置需要在代码中手动去确认消费者消费消息成功&…

浅谈Mysql Innodb存储引擎

一、Mysql整体架构 二、MySQL 5.7 支持的存储引擎 类型 描述 MyISAM 拥有较高的插入、查询速度&#xff0c;但不支持事务 InnoDB 5.5版本后Mysql的默认数据库&#xff0c;5.6版本后支持全文索引&#xff0c;事务型数据库的首选引擎&#xff0c;支持ACID事务&#xff0c;支…

Android Lint

文章目录 Android Lint概述工作流程Lint 问题问题种类警告严重性检查规则 用命令运行 LintAndroidStudio 使用 Lint忽略 Lint 警告gradle 配置 Lint查找无用资源文件 Android Lint 概述 Lint 是 Android 提供的 代码扫描分析工具&#xff0c;它可以帮助我们发现代码结构/质量…

linux中 nginx+tomcat 部署方式 tomcat挂掉设置自动启动

在Linux环境下&#xff0c;要实现当Tomcat挂掉后自动重启&#xff0c;可以通过编写Shell脚本结合cron定时任务或者使用系统守护进程&#xff08;如Systemd、Upstart或SysVinit&#xff09;来完成。 使用Shell脚本和cron定时任务 编写检查并重启Tomcat的Shell脚本&#xff1a;首…

为什么网络爬虫广泛使用HTTP代理?

一、引言 网络爬虫作为自动抓取互联网信息的重要工具&#xff0c;在现代社会中发挥着不可或缺的作用。然而随着网络环境的日益复杂&#xff0c;网站反爬虫技术的不断进步&#xff0c;网络爬虫在获取数据的过程中面临着越来越多的挑战。为了应对这些挑战&#xff0c;HTTP 代理成…

Python容器 之 字符串--定义

目录 1.字符串如何定义&#xff1f; 2.定义字符串时遇到特殊内容怎么处理&#xff1f; 1)字符串本身包含引号&#xff0c;如&#xff1a;定义字符串 Im 小明、他叫“小明”。 &#xff08;1&#xff09;如果字符串本身包含单引号,定义的时候不能使用 单引号。 &#xff08…

【Linux】Linux下使用套接字进行网络编程

&#x1f525;博客主页&#xff1a; 我要成为C领域大神&#x1f3a5;系列专栏&#xff1a;【C核心编程】 【计算机网络】 【Linux编程】 【操作系统】 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 本博客致力于知识分享&#xff0c;与更多的人进行学习交流 ​ 用于网络应用开…

SAP 替代关系完全替代简介

最近用户在对长周期物料进行备料的时候又提出替代料的问题,主料库存不足的时候需要考虑替代料的在途库存,经常会忘了SAP标准的替代料逻辑,这次一次性把这个逻辑写清楚。 关于替代料的逻辑在前面的博文中测试多个替代料的使用场景 1、后继物料 2、组合替代 本文主要测试一下…

Sentinel如何使用BlockExceptionHandler实现限流/降级错误页面显示

1、修改配置项&#xff0c;打开对Spring MVC端点的保护 spring.cloud.sentinel.filter.enabledtrue 2、编写 BlockExceptionHandler的实现类 MyUrlBlockHandler.java package com.codex.terry.sentinel.urlblockhandler;/*** 文件名称: MyUrlBlockHandler.java* 编写人: yh…