文章目录

  • Socket编程UDP
    • UDP接口的使用铺垫
      • socket
      • recvform && sendto
      • bind
    • 字节序转化使用(Tips)
    • 实践部分
      • version_1@echo_server
      • version_2@dict_server
      • version_3@chat_server

Socket编程UDP

在了解了相关的网络基础知识后,我们不会像学系统知识一样,先学原理,再讲应用。
我们先先不选择学习网络原理。我们先来试着学习一下使用接口来完成一些简单地实践。

在这个部分中,我们不只使用网络相关知识,而是结合前面系统部分学习时,完成的一些组件代码来使用!这些我们后面会见到的!

UDP接口的使用铺垫

先说一下,有了网络基础知识 + 系统部分的知识。其实我们只需要了解一下UDP相关接口的使用,其实就能较为熟练地学习如何使用。下面,我们将把网络中将用的接口进行简单讲解。

socket

NAMEsocket - create an endpoint for communication //打开通信的一端SYNOPSIS#include <sys/types.h>          /* See NOTES */#include <sys/socket.h>int socket(int domain, int type, int protocol);

这个文件,是用来创建套接字的!我们在网络基础部分讲过,两个进程的通信是基于套接字(端口号 + ip)的!具体的创建,就是用这个接口。

第一个参数domain是选择使用什么域来进行通信:
在这里插入图片描述
这里我们记住是选择AF_INET进行网络通信即可!

第二个参数type是选择使用什么方式传输,比如TCP/UDP:
在这里插入图片描述
字符流 -> SOCK_STREAM -> TCP
数据包 -> SOCK_DGRAM -> UDP

第三个参数protocol是要我们选择协议,默认给0就是TCP/IP了,记住即可!

返回值:
在这里插入图片描述
成功,返回一个file descriptor,即文件描述符!即使我们不知道这个网络通信的原理,但是我们至少可以直到,当前进程的文件描述符表定会有一个位置指向socket文件!

所以,我们就把它当成特殊的网络文件来使用!这符合 Linux下一切皆文件!

recvform && sendto

我们先来看着两个函数的相关信息,它们具有较强相似性:

recvform

NAMErecv, recvfrom, recvmsg - receive a message from a socketSYNOPSIS#include <sys/types.h>#include <sys/socket.h>ssize_t recv(int sockfd, void *buf, size_t len, int flags);ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);RETURN VALUEThese calls return the number of bytes received, or -1 if an error occurred.  In the event of an error, errno is set to indicate the error.

sendto

NAMEsend, sendto, sendmsg - send a message on a socketSYNOPSIS#include <sys/types.h>#include <sys/socket.h>ssize_t send(int sockfd, const void *buf, size_t len, int flags);ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);RETURN VALUEOn success, these calls return the number of bytes sent.  On error, -1 is returned, and errno is set appropriately.

见名思意:
recvform是从套接字文件中获取内容;sendto是向套接字文件中发送内容。


参数解释:

  1. int sockfd,就是对应的套接字文件!这个不需要解释。

  2. const void *buf,这个就是一个缓冲区,recvfrom把从套接字文件中读到的内容读取到该缓冲区。sendto将该缓冲区内的内容发送到套接字文件。

  3. size_t len,即缓冲区长度。

  4. int flags,这个是选择是否阻塞读取/发送的。默认给0就是阻塞。也就是说,recvfrom读不到内容就会阻塞,sendto没有内容发送也会阻塞。这个我们在系统那里也见过。

  5. struct sockaddr,这个其实我们早在网络基础部分的时候,就已经讲到过这个。我们说了,设计socket网络通信的时候,为了能够让网络通信和本地通信公用一套接口,所以设计了这么个c语言版的基类

    所以,如果需要收发消息,其实对方进程的相关信息:ip、端口号、通信协议,都会在对应的结构体上体现出来。所以,未来在使用socket通信的时候,如何知道或者发送自己的相关信息,就是靠着这个结构体sockaddr_in或者sockaddr_un,强转类型为sockaddr对应的地址变量后,然后进行相关操作!

6.socklen_t *addrlensocklen_t addrlen
6.1. 对于recvfrom收消息来说,参数是socklen_t *addrlen,这很明显是一个指针地址变量!所以,是需要我们把sockaddr_in的地址传进去给第五个参数,然后需要定义一个变量指明该结构体大小,传入地址给第六个参数。
Tips:因为该变量是输出型参数,实际上它会返回真正读到的字节数(因为网络传输可能丢包)

6.2. 对于sendto发消息来说,这个就没什么好说的了,本身数据就在,直接传对应的大小即可

bind

NAMEbind - bind a name to a socketSYNOPSIS#include <sys/types.h>          /* See NOTES */#include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);RETURN VALUEOn success, zero is returned.  On error, -1 is returned, and errno is set appropriately.

没看错,这里还有一个接口叫做bind,但是,这个不是c++11后提出的std::bind

这个接口最重要的就是,将套接字文件和对应的进程的IP地址和端口号(在结构体sockaddr_in内存储了),绑定到对应的套接字文件中!

​​bind的作用​​:
显式绑定:bind()将套接字固定到特定IP+端口,成为该地址的唯一接收者。
未绑定时:系统在首次发送数据时自动分配随机端口(IP默认为所有本地接口)

这里理解一下就好,实在看不懂的话等后续讲解的时候再说一遍如何使用。现在只需要学会使用即可,原理等后期再来讲解!

字节序转化使用(Tips)

这个在网络基础中也是提到了。这里再多提醒一下,因为后续的实践中,必然是有从网络序列转主机序列的内容,也有主机序列转网络序列的!所以,这些是必须使用的!
在这里插入图片描述

实践部分

version_1@echo_server

源码:version_1@echo_server

第一个版本,我们希望实现一种功能:
即有一个服务器,然后其余所有的进程都可以给其发消息,然后服务器处理后再转发给对应的进程,这样子就起到了一个回显服务器的效果!

所有的过程都已经在代码的注释中展现出来了。

version_2@dict_server

源码:version_2@dict_server

第二个版本,其实就是进行一次解耦合!让第一个版本中对于信息回显的处理模块,转化为服务器调用词典翻译模块!其实主要的逻辑和第一个版本差别不大。

只不过是引入多了一个模块,让词典从对应的配置文件中读取对应信息,然后服务器进行调用后再进行转发结果给请求该服务的进程!

version_3@chat_server

源码:version_3@chat_server

第三个版本我们来详细说明一下:
第三个版本我们希望做到一个群聊转发功能,即服务器在接收到某个客户端发送来的消息后,要转发给所有处于在线的用户。

1.我们这里规定:
默认第一次发送消息的就是要加入群聊的。服务器接收到消息之后,要怎么样才能转发给所有的在线用户呢?-> 添加一层路由层,用于管理在线用户(组织描述)和消息转发!

2.但是,我们觉得效率太低了,所以希望的是,服务器将收到的信息推给后端线程池,让线程池自行调用路由转发功能!所以引入了线程池。

3.此前版本1、2写的客户端使用代码是有问题的!因为强行规定了先发消息才能收消息。所以,在实现群聊过程中,发现客户端只有发了消息,才能接收到其他客户端被转发的消息。所以,为此我们进行了处理,就是让客户端多线程处理!即创建两个线程,同时进行收发!

4.线程池访问路由表的时候(就是底层的一个哈希),也是会涉及到线程安全的。但是,因为今天的实现并没有规定消息的协议(是否退出、私法、群发、还是请求服务器处理…)。我们仅仅只是把收到的内容当字符串处理!
但是不管怎么说,线程池内每个线程访问的时候,是会出现数据不一致的问题的!因为STL不是线程安全的,所以我们这里就粗暴一点,直接加锁!

5.实践的时候,因为我没有多台Linux机器,所以,使用了Windows进行辅助测试,测试是否能够跨网通信!代码如下:

#include <iostream>
#include <cstdio>
#include <thread>
#include <string>
#include <cstdlib>
#include <WinSock2.h>
#include <Windows.h>#pragma warning(disable : 4996)#pragma comment(lib, "ws2_32.lib")std::string serverip = "";  // 填写你的云服务器ip
uint16_t serverport = ; // 填写你的云服务开放的端口号SOCKET sockfd; 
struct sockaddr_in server;void recv_msg() {while (1) {char buffer[1024];struct sockaddr_in temp;int len = sizeof(temp);int s = recvfrom(sockfd, buffer, 1023, 0, (struct sockaddr*)&temp, &len);if (s > 0){buffer[s] = 0;std::cout << buffer << std::endl;}}
}void send_msg() {memset(&server, 0, sizeof(server)); server.sin_family = AF_INET; server.sin_port = htons(serverport); //? server.sin_addr.s_addr = inet_addr(serverip.c_str()); while (1) {std::string message; std::getline(std::cin, message);if (message.empty()) continue; sendto(sockfd, message.c_str(), (int)message.size(), 0, (struct sockaddr*)&server, sizeof(server));}
}int main() {WSADATA wsd; WSAStartup(MAKEWORD(2, 2), &wsd); sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd == SOCKET_ERROR){std::cout << "socker error" << std::endl;return 1;}std::thread Recv(recv_msg);std::thread Send(send_msg);Recv.join();Send.join();closesocket(sockfd);WSACleanup();return 0;
}//int main()
//{
//    WSADATA wsd;
//    WSAStartup(MAKEWORD(2, 2), &wsd);
//
//
//    memset(&server, 0, sizeof(server));
//    server.sin_family = AF_INET;
//    server.sin_port = htons(serverport); //?
//    server.sin_addr.s_addr = inet_addr(serverip.c_str());
//
//    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
//    if (sockfd == SOCKET_ERROR)
//    {
//        std::cout << "socker error" << std::endl;
//        return 1;
//    }
//
//
//
//    std::string message;
//    char buffer[1024];
//    while (true)
//    {
//        std::cout << "please input: ";
//        std::getline(std::cin, message);
//        if (message.empty()) continue;
//        sendto(sockfd, message.c_str(), (int)message.size(), 0, (struct sockaddr*)&server, sizeof(server));
//        struct sockaddr_in temp;
//        int len = sizeof(temp);
//        int s = recvfrom(sockfd, buffer, 1023, 0, (struct sockaddr*)&temp, &len);
//        if (s > 0)
//        {
//            buffer[s] = 0;
//            std::cout << buffer << std::endl;
//        }
//    }
//
//    closesocket(sockfd);
//    WSACleanup();
//    return 0;
//}

前面一份是用于版本3的测试,后面是用于版本1、2的测试!这里可以搜一下相关大模型了解一下用法,其实用法和Linux下的基本一致。

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

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

相关文章

GD32 波形发生器,三角波,正弦波,方波。AD9833+MCP410生成和MCU自身的DAC生成。波形,频率,振幅可以通过按键和OLED调整输出。

DIY一个简易的信号发生器驱动板&#xff0c;主要是三角波和正弦波&#xff0c;方波。主板有两个通道能输出波形&#xff0c;CH0由AD9833MCP410AD8051放大电路组成&#xff0c;理论可以生成0.1-12.5MHZ的频率信号&#xff0c;单电源振幅范围是1-9V。CH1由MCU外设DAC生成的信号&a…

VS2022的MFC中关联使用控制台并用printf输出调试信息

前言 MFC一般在调试的时候&#xff0c;可以在IDE中方便的看到调试的信息。但是&#xff0c;有时候运行的时候也要看调试的信息怎么办&#xff1f;最好如同在Console&#xff08;控制台&#xff09;程序中输出一般的方便&#xff0c;可以么&#xff1f;可以的。 一、设置 1.1、加…

ZKmall模块商城的推荐数据体系:从多维度采集到高效存储的实践

在电商领域&#xff0c;个性化推荐已成为提升用户体验与转化效率的核心手段。ZKmall 模块商城基于用户行为、商品属性与交易数据&#xff0c;构建了一套完整的推荐算法体系&#xff0c;而数据采集的全面性与存储的高效性是该体系的基础。本文将聚焦推荐算法的 “数据输入端”&a…

Qt + windows+exe+msvc打包教程

目录 1. Qt + windows+exe+msvc打包教程1 1.1. Enigma Virtual Box下载⏬1 1.2. Enigma Virtual Box安装2 1.3. Qt 打包成独立exe教程6 1.3.1. Qt项目创建6 1.3.2. Qt项目编译13 1.3.3. Qt 项目打包 windeployqt命令14 1.3.4. Qt 项目打包 Enigma Virtual Box工具18 Q…

大语言模型应用开发——利用OpenAI函数与LangChain结合从文本构建知识图谱搭建RAG应用全流程

概述 从文本等非结构化数据中提取结构化信息并非新鲜事物&#xff0c;但大语言模型&#xff08;LLMs&#xff09;为该领域带来了重大变革。以往需要机器学习专家团队策划数据集并训练自定义模型&#xff0c;如今只需访问LLM即可实现&#xff0c;显著降低了技术门槛&#xff0c…

Vue3+Spring Boot技术栈,前端提交混合表单数据(普通字段+文件字段),上传文件,后端插入数据,将文件保存到数据库

一、技术栈1、前端 Vue3 Element Plus TypeSprict2、后端 Spring Boot 3.2.12 Mybatis Plus3、模型特点3.1、表格展示列表数据3.2、行点击&#xff0c;弹出对话框3.3、前端使用 FormData 提交混合表单数据&#xff0c;包含普通字段和文件字段3.4、文件对应数据库结构类型为 …

【Qt开发】Qt的背景介绍(四)

目录 1 -> Qt Hello World 程序 1.1 -> 使用“按钮”实现 1.1.1 -> 纯代码方式实现 1.1.2 -> 可视化操作实现 1.2 -> 使用“标签”实现 1.2.1 -> 纯代码方式实现 1.2.2 -> 可视化操作实现 2 -> 项目文件解析 2.1 -> .pro文件解析 2.2 -&g…

Linux驱动开发笔记(六)——pinctrl GPIO

开发板&#xff1a;imx6ull mini 虚拟机&#xff1a;VMware17 ubuntu&#xff1a;ubuntu20.04 视频&#xff1a;第8.1讲 pinctrl和gpio子系统试验-pincrl子系统详解_哔哩哔哩_bilibili 文档&#xff1a;《【正点原子】I.MX6U嵌入式Linux驱动开发指南.pdf》四十五章 这一章…

SpringBoot 快速上手:从环境搭建到 HelloWorld 实战

在 Java 开发领域&#xff0c;Spring 框架占据着举足轻重的地位&#xff0c;但它复杂的配置曾让不少开发者望而却步。SpringBoot 的出现&#xff0c;如同为 Spring 框架装上了 “加速器”&#xff0c;以 “约定大于配置” 的理念简化了开发流程。本文将从环境准备、Maven 配置入…

图、最小生成树与最短路径

目录 并查集 并查集实现 图 概念 图的存储结构 邻接矩阵 邻接表 无向图 有向图 图的遍历 广度优先遍历 深度优先遍历 最小生成树 Kruskal算法&#xff08;克鲁斯卡尔算法&#xff09; Prim算法&#xff08;普利姆算法&#xff09; 最短路径 单源最短路径--Dij…

互联网电商新生态:开源AI智能名片、链动2+1模式与S2B2C商城小程序的融合赋能

摘要&#xff1a;本文聚焦互联网电商领域&#xff0c;探讨在当下直播电商蓬勃发展的背景下&#xff0c;开源AI智能名片、链动21模式以及S2B2C商城小程序如何相互融合&#xff0c;为创业者、企业和淘宝主播IP等电商参与者带来新的发展机遇。通过分析各要素的特点与优势&#xff…

企业车辆|基于SprinBoot+vue的企业车辆管理系统(源码+数据库+文档)

企业车辆管理系统 基于SprinBootvue的企业车辆管理系统 一、前言 二、系统设计 三、系统功能设计 系统功能实现 后台模块实现 管理员模块实现 驾驶员模块实现 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博…

自学嵌入式第二十五天:数据结构-队列、树

一、队列队列是只允许一段进行插入&#xff0c;另一端进行删除操作的线性表&#xff1b;允许插入的一端叫队尾&#xff0c;允许删除的一端叫对头&#xff1b;先进先出&#xff1b;用于解决速度不匹配&#xff08;例如一快一慢&#xff09;&#xff0c;做缓冲用&#xff1b;二、…

MySQL索引原理与优化全解析

1、MySQL索引是什么&#xff1f; 在关系数据库中&#xff0c;索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构&#xff0c;它是某个表中一列或若干列值的集合和相应的指向表中物理标志这些值的数据页的逻辑指针清单。索引的作用相当于图书的目录&a…

模型对话状态管理方法详解

模型对话状态管理方法详解 目录 简介手动管理对话状态构建对话历史追加响应内容 API 支持的自动化对话状态管理使用 previous_response_id 链接话轮 Token 及上下文窗口管理上下文窗口定义与限制Token 计数与工具 安全与合规注意事项结语1. 简介 在多轮对话场景中&#xff0c;合…

GPT-5 上线风波深度复盘:从口碑两极到策略调整,OpenAI 的变与不变

摘要&#xff1a; 近日&#xff0c;备受瞩目的 GPT-5 正式上线&#xff0c;却意外地在社区引发了两极化争议。面对技术故障与用户质疑&#xff0c;OpenAI 迅速推出一系列补救措施。本文将深度复盘此次发布风波&#xff0c;解析其背后的技术挑战与应对策略&#xff0c;并探讨这一…

【Android】使用FragmentManager动态添加片段

三三要成为安卓糕手 上一篇文章&#xff0c;我们是在xml中静态添加fragment&#xff0c;但是一些修改或者其他事情是做不了的&#xff1b; 本章我们达成在java代码中灵活添加、删除、替换fragment操作 一&#xff1a;核心代码展示 简单做一个这种页面public class FragmentActi…

MiniOB环境部署开发(使用开源学堂)

整体思路&#xff1a; 1.使用开源学堂在线编程环境开发MiniOB编译环境 2.使用vscode进行代码调试和开发以及上传到仓库 MiniOB源码&#xff1a;https://github.com/oceanbase/miniob MiniOB文档&#xff1a;MiniOB 介绍 - MiniOB 数据库大赛官网&#xff1a;OceanBase 社区…

09_常用内置模块进阶

第9课&#xff1a;常用内置模块进阶 课程目标 深入学习Python常用内置模块掌握collections、itertools、functools等模块学习json、csv、pickle等数据处理模块 1. collections模块 1.1 Counter类 from collections import Counter# 统计元素出现次数 text "hello world p…

⚡ Ranger 基础命令与功能详解

&#x1f4cc; 1. Ranger简介 Ranger&#xff08;游侠&#xff09;是一款 Linux 专用的 指令式文件管理器&#xff0c;其操作风格类似 Vim&#xff0c;通过输入指令即可完成目录跳转、文件编辑、移动、复制等操作。 相比于 mc&#xff08;Midnight Commander&#xff09;&…