当前位置: 首页 > news >正文

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分

相关文章:

Linux网络编程:套接字编程

1.Socket套接字编程 1.1.什么是socket套接字编程 Socket套接字编程 是一种基于网络层和传输层网络通信方式&#xff0c;它允许不同主机上的应用程序之间进行双向的数据通信。Socket是网络通信的基本构件&#xff0c;它提供了不同主机间的进程间通信端点的抽象。一个Socket就是…...

多电商账户为什么要用指纹浏览器?

随着电子商务的蓬勃发展&#xff0c;越来越多的商家选择开设多店来扩大经营规模。然而多店运营也带来了一系列的挑战&#xff0c;其中之一就是账号安全。 1. 了解反检测浏览器和代理服务器 在我们开始讨论如何有效地使用反检测浏览器之前&#xff0c;我们首先需要了解这两个工…...

用Rancher2.8.5部署K8s集群

参考&#xff1a;通过Rancher 2.7.5部署企业生产级K8s集群 新K8s集群的环境信息 Rancher1台&#xff0c;K8s集群6台&#xff08;1台rancher&#xff0c;3台master&#xff0c;4台node&#xff09;。 Name|lmage Name|IP Address|Flavor|Comment project-root-dev-rancher|Ro…...

未来已来,如何打造智慧养殖场?

近年来&#xff0c;国家出台了一系列扶持政策&#xff0c;以促进养殖行业高质量发展&#xff0c;推动行业转型升级。在国家政策和市场需求的双重驱动下&#xff0c;养殖行业正迎来前所未有的发展机遇。智慧养殖以其高效、智能和可持续的特点&#xff0c;正逐步取代传统养殖方式…...

代码随想录算法训练营第七天|454.四数相加II、383. 赎金信、15. 三数之和、18. 四数之和

打卡Day7 1.454.四数相加II2.383. 赎金信3.15. 三数之和4.18. 四数之和 1.454.四数相加II 题目链接&#xff1a;四数相加II 文档讲解&#xff1a; 代码随想录 class Solution {public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {int res 0;Map…...

Python和tkinter实现的字母记忆配对游戏

Python和tkinter实现的字母记忆配对游戏 因为这个小游戏用到了tkinter&#xff0c;先简要介绍一下它。tkinter是Python的标准GUI(图形用户界面)库&#xff0c;它提供了一种简单而强大的方式来创建图形界面应用程序。它提供了创建基本图形界面所需的所有工具&#xff0c;同时保…...

Leetcode Hot100之链表

1.相交链表 解题思路 快慢指针&#xff1a;分别求出两个链表的长度n1和n2&#xff0c;在长度较长的那个链表上&#xff0c;快指针先走n2 - n1&#xff0c;慢指针再出发&#xff0c;最后能相遇则链表相交 时间复杂度O(mn)&#xff0c;空间复杂度O(1)代码# Definition for singl…...

5.9k!一款清新好用的后台管理系统!【送源码】

今天给大家分享的开源项目是一个优雅清新后台管理系统——Soybean Admin。 简介 官方是这样介绍这个项目的&#xff1a; Soybean Admin 使用的是Vue3作为前端框架&#xff0c;TypeScript作为开发语言&#xff0c;同时还整合了NaiveUI组件库&#xff0c;使得系统具有高可用性和…...

Vue-cli搭建项目----基础版

什么是Vue-cli 全称:Vue command line interface 是一个用于快速搭建Vue.js项目的标准工具,他简化了Vue.js应用的创建和管理过程,通过命令工具帮助开发者快速生成,配置和管理Vue项目. 主要功能 同一的目录结构本地调试热部署单元测试集成打包上线 具体操作 第一步创建项目:…...

python之__call__函数介绍

Python 中的 __call__ 方法是一种特殊的方法,它允许对象像函数一样被调用。当你创建一个对象并使用括号 () 调用它时,Python 会自动调用这个对象的 __call__ 方法。 1. 基本用法 下面是一个简单的例子: class MyClass:def __init__(self, value):self.value valued…...

【AI】生成式AI服务器最低配置

【背景】 考虑数据安全&#xff0c;又想用AI赋能企业内部的日常工作&#xff0c;答案只有一个&#xff0c;本地部署。 UI采用open-web-ui&#xff0c;模型用Ollama管理&#xff0c;在局域网做成SAAS服务。要组一个服务器&#xff0c;提供部门内部最多30个的API并发。以下为反复…...

2.Android逆向协议-了解常用的逆向工具

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a;微尘网校 上一个内容&#xff1a;1.Android逆向协议-环境搭建 常用的工具&#xff1a;AndroidKiller、jadx、JEB、IDA AndroidKiller…...

大数据------额外软件、插件及技术------Linux(完整知识点汇总)

Linxu 不同领域的主流操作系统 桌面操作系统 WindowsMAac OSLinux 服务器端操作系统 UNIX&#xff08;付费&#xff09;LinuxWindows Server&#xff08;付费&#xff09; 移动设备操作系统 Android&#xff08;基于Linux开源&#xff09;IOS&#xff08;不开源&#xff09; 嵌…...

iOS 其他应用的文件如何在分享中使用自己的应用打开

废话少说 一、第一步&#xff1a;先配置好plist文件 右击info.plist如下图文件打开 根据自己需要配置支持的文件类型&#xff0c;也可使用property List中配置&#xff0c;一样的 其他的文件可是参考文档&#xff1a;System-Declared Uniform Type Identifiers 可复制的代码&am…...

【编译原理必考大题】 推导构建语法树,写出语法树的短语,简单短语和句柄

写在最前 本文为编译原理重点考察大题之一&#xff0c;理论基础见专栏文章&#xff0c;0基础直接使用也可食用 文章目录 推导构造语法树1.语法树的概念2. 子树&#xff0c;短语&#xff0c;简单短语&#xff0c;句柄2.1 子树2.2 短语2.3 简单短语与句柄2.4 真题实战 推导构造语…...

redis服务介绍

redis 基础概念安装使用基础操作命令数据类型操作命令 管理和维护命令 基础概念 Remote Dictionary Server&#xff08;Redis&#xff09;远程字典服务器是完全开源免费的&#xff0c;用C语言编写的&#xff0c;遵守BSD开源协议&#xff0c;是一个高性能的&#xff08;key/val…...

nodepad 中换行符、tab替换

1 nodepad 主要符号 换行符: \r\n&#xff08;windows&#xff09; tab: \t 2 展示符号 3 相互替换 tip:需要点击扩展 参考&#xff1a; https://blog.csdn.net/lijing742180/article/details/85174564...

常见的字符串函数(包含头文件string.h)和字符函数(2)

八. strstr函数 1.strstr的定义 char *strstr( const char *str1, const char *str2 ); ->1. strstr查找子串(str2)在字符串(str2)中第一次出现的位置&#xff0c;记录并返回该位置的指针&#xff0c;如果找不到&#xff0c;则返回NULL ->2. str1&#xff1a;查找字符…...

Python | Leetcode Python题解之第187题重复的DNA序列

题目&#xff1a; 题解&#xff1a; L 10 bin {A: 0, C: 1, G: 2, T: 3}class Solution:def findRepeatedDnaSequences(self, s: str) -> List[str]:n len(s)if n < L:return []ans []x 0for ch in s[:L - 1]:x (x << 2) | bin[ch]cnt defaultdict(int)for…...

SpringCloud分布式微服务链路追踪方案:Skywalking

一、引言 随着微服务架构的广泛应用&#xff0c;系统的复杂性也随之增加。在这种复杂的系统中&#xff0c;应用通常由多个相互独立的服务组成&#xff0c;每个服务可能分布在不同的主机上。微服务架构虽然提高了系统的灵活性和可扩展性&#xff0c;但也带来了新的挑战&#xf…...

springboot 百货中心供应链管理系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;百货中心供应链管理系统被用户普遍使用&#xff0c;为方…...

YSYX学习记录(八)

C语言&#xff0c;练习0&#xff1a; 先创建一个文件夹&#xff0c;我用的是物理机&#xff1a; 安装build-essential 练习1&#xff1a; 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件&#xff0c;随机修改或删除一部分&#xff0c;之后…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

SpringCloudGateway 自定义局部过滤器

场景&#xff1a; 将所有请求转化为同一路径请求&#xff08;方便穿网配置&#xff09;在请求头内标识原来路径&#xff0c;然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...

JVM 内存结构 详解

内存结构 运行时数据区&#xff1a; Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器&#xff1a; ​ 线程私有&#xff0c;程序控制流的指示器&#xff0c;分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 ​ 每个线程都有一个程序计数…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖

在Vuzix M400 AR智能眼镜的助力下&#xff0c;卢森堡罗伯特舒曼医院&#xff08;the Robert Schuman Hospitals, HRS&#xff09;凭借在无菌制剂生产流程中引入增强现实技术&#xff08;AR&#xff09;创新项目&#xff0c;荣获了2024年6月7日由卢森堡医院药剂师协会&#xff0…...

Java数值运算常见陷阱与规避方法

整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

DingDing机器人群消息推送

文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人&#xff0c;点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置&#xff0c;详见说明文档 成功后&#xff0c;记录Webhook 2 API文档说明 点击设置说明 查看自…...