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

Linux网络——socket编程与UDP实现服务器与客户机通信

文章目录

    • 端口号
    • TCP/UDP
    • 网络字节序
    • socket的常见API
    • UDP实现服务器与客户机通信
      • 服务器
      • 客户机
      • 运行效果如下

端口号

我们说即便是计算机网络,他们之间的通信也仍然是进程间通信

那么要如何在这么多计算机中,找到你想要的那个进程呢

在网络中标识的唯一的计算机使用的是ip地址

在同一台计算机的进程是通过进程id区分的,而要在对方的计算机中按照进程id来找恐怕不是一共好的想法,因为你也不知道对方进程的id是多少,于是就商量(传输层协议)使用port端口来确定进程

因此ip加上port就能确定这个世界上的唯一一台计算机中的唯一一个进程

ip地址是用四个八位二进制数来表示

而port端口号是一共2字节16位整数

端口号用来标识进程,告诉操作系统数据要交给哪一个进程

都已经有了进程id了为什么还要有个端口号呢

这是因为一个端口号只能被一个进程占用,但是一个进程是可以拥有多个端口号的

他们之间并不是完美的1对1关系

TCP/UDP

我们先简单重新认识一下这两个协议

这两个都是传输层的协议

TCP面向的是有连接,意思是在正式的传递信息之前,需要建立连接,确保是能收到的,就像对暗号一样,土豆土豆我是地瓜

而UDP则是无连接的,相当于直接把数据扔出去

640?wx_fmt=jpeg

img

由此可见,TCP是可靠传输,他规定了一些措施来保证传输的可靠性,例如三次握手四次挥手

“嗨,我想听一个TCP的笑话。”

“你好,你想听 TCP 的笑话么?”

“嗯,我想听一个 TCP 的笑话。”

“好的,我会给你讲一个TCP 的笑话。”

“好的,我会听一个TCP 的笑话。”

“你准备好听一个TCP 的笑话么?”

“嗯,我准备好听一个TCP 的笑话”

“OK,那我要发 TCP 笑话了。大概有 10 秒,20 个字。”

“嗯,我准备收你那个 10 秒时长,20 个字的笑话了。”

“抱歉,你的链接超时了。你好,你想听 TCP 的笑话么?”

而UDP是完全没有的,因此他是不可靠的

我给你们讲个UDP 的笑话吧! 哈哈哈哈哈哈哈哈哈是不是很好笑

除此之外,TCP由于建立了连接,就可以像水流一样传输数据,是面向字节流的,而UDP则没有,所以UDP是面向数据包的

网络字节序

计算机内存分为大端存储和小端存储,大端存储是低地址存高位数据,小端存储是低地址存低位数据

在这里插入图片描述

至今这两个流派也没有分出胜负,但是计算机网络不知道啊,他不知道两个计算机之间是如何存储的,只能硬性规定,网络数据流是按照低地址存高位数据,也就是大端存储

发送方的主机发送时是按照地址从低到高发送的

如果发送方是小端,则先将数据传换成大端

我们可以使用系统调用,将大小端字节序进行交换

在这里插入图片描述

也就是说小端机器发送时,调用hton,小端机器接收时,调用ntoh

大端直接就原封不动返回了,因此不确定大小端时,调用就对了

socket的常见API

socket有一个媲美鲁棒性的翻译,套接字,让人看得云里雾里,简直是完美的反自学机制

在这里插入图片描述

套接字的本质就是一个文件描述符,这个东西非常非常非常重要

在这里插入图片描述

socket的第一个参数是标识套接字的类型,AF_INET表示IPv4,也是最常用的

第二个参数表示通信的类型,是使用UDP(SOCK_DGRAM)还是使用TCP(SOCK_STREAM)

bind的作用是将这个进程提供的服务绑定到操作系统中,当外部访问时就能知道这个服务的端口号,当信息发出时,也能携带自身的ip和port

listen和accept是TCP通信中需要用到的,listen用于开始监听是否有请求,accept用于将拿到的请求解析,connect则是连接的请求

接下来我们会使用UDP进行主机和服务器之间的通信

UDP实现服务器与客户机通信

首先我们需要知道的是客户机和服务器需要的程序是不一样的,因此需要分别实现服务器和客户机的代码

我们需要知道,所谓的服务器和客户机不过都是进程

服务器

服务器的代码相对复杂,我们分不同文件来说明

// nocopy.hpp
#pragma once
#include <iostream>
class nocopy
{
public:nocopy() {}nocopy(const nocopy &) = delete;const nocopy &operator=(const nocopy &) = delete;~nocopy() {}
};

这个类主要是实现一个最简单的单例模式,防止服务器进程被拷贝等内容

#pragma once
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>class InetAddr // 将接收到的网络信息格式化
{
public:InetAddr(struct sockaddr_in &addr): _addr(addr){_port = ntohs(_addr.sin_port);   // 将网络字节序转换为主机字节序_ip = inet_ntoa(_addr.sin_addr); // 将网络字节序的IP转换为点分十进制的字符串}std::string Ip(){return _ip;}uint16_t Port(){return _port;}std::string PrintDebug() // 输出调试信息{std::string info = _ip;info += ':';info += std::to_string(_port);return info;}~InetAddr() {}private:std::string _ip;uint16_t _port;struct sockaddr_in _addr;
};

这个类主要是给客户机提供一个存储客户机信息的类,用于返回给客户机的请求

#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "nocopy.hpp"
#include "InetAddr.hpp"const static uint16_t defaultport = 1141; // 默认端口号
const static uint16_t defaultfd = -1;     // 默认socket
const static uint16_t defaultsize = 1024; // 默认缓冲区大小class UdpServer : public nocopy // 服务器不允许被拷贝,简化的单例模式
{
public:UdpServer(uint16_t port = 11451): _port(port){}void Init(){// 创建socket文件描述符,对其进行初始化_sockfd = socket(AF_INET, SOCK_DGRAM, 0); // 使用IPv4,UDP协议if (_sockfd < 0){perror("socket创建失败");exit(errno);}std::cout << "socket创建成功,文件描述符为:" << _sockfd << std::endl;// 初始化网络信息struct sockaddr_in local;bzero(&local, sizeof(local));       // memsetlocal.sin_family = AF_INET;         // 协议簇local.sin_port = htons(_port);      // 端口号local.sin_addr.s_addr = INADDR_ANY; // ip地址// 绑定到系统内核int n = bind(_sockfd, (struct sockaddr *)&local, sizeof(local));if (n != 0){perror("bind出错");exit(errno);}}void Start() // 服务器不退出{char buffer[1024];for (;;){struct sockaddr_in peer; // 远程地址信息,因为需要返回请求socklen_t len = sizeof(peer);ssize_t n = recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len); // 获取从从外部接收的数据// 第一个参数是套接字文件描述符,标识接收数据的套接字// 第二个参数是接收数据的缓冲区if (n > 0) // 正确接收{InetAddr addr(peer); // 格式化网络信息buffer[n] = '\0';    // 手动添加结束std::cout << '[' << addr.PrintDebug() << "]# " << buffer << std::endl;sendto(_sockfd, buffer, strlen(buffer), 0, (struct sockaddr *)&peer, len);}}}~UdpServer(){}private:uint16_t _port; // 端口号int _sockfd;    // socket文件描述符
};

这里就是客户机的主体了,里面的代码和注释写的非常详细,主要思路就是初始化,先听,后回复

#include "udpserver.hpp"
#include <memory>void Usage(std::string proc) // 使用提示
{std::cout << "Usage:\n\t" << proc << "local_port\n"<< std::endl;
}int main(int argc, char *argv[])
{if (argc != 2){Usage(argv[0]);return 1;}uint16_t port = std::stoi(argv[1]);std::unique_ptr<UdpServer> usvr = std::make_unique<UdpServer>(port);usvr->Init();usvr->Start();return 0;
}

这里就是主程序,负责判断用户输入是否正确,调用服务器

客户机

#include <iostream>
#include <cerrno>
#include <cstring>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>void Usage (const std::string &proc)
{std::cout<<"Usage:\n\t"<<proc<<"server_ip server_port" <<std::endl;
}int main(int argc, char* argv[])
{if(argc!=3){Usage(argv[0]);return 1;    }std::string serverip = argv[1];uint16_t serverport = std::stoi(argv[2]);// 创建socketint sockfd = socket(AF_INET, SOCK_DGRAM, 0);if(sockfd<0){perror("socket创建失败");exit(errno);}std::cout<<"socket创建成功,sockfd:"<<sockfd<<std::endl;// 客户机也需要绑定,但是不需要主动调用,客户机会在第一次发送数据时自动绑定数据// 填充服务器信息struct sockaddr_in server;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(true){// 发送的数据std::string inbuffer;std::cout<<"Please Enter# ";std::getline(std::cin, inbuffer);// 发送消息(请求)ssize_t n = sendto(sockfd, inbuffer.c_str(), inbuffer.size(), 0, (struct sockaddr*)&server, sizeof(server));// 收消息if(n>0){char buffer[1024];struct sockaddr_in tmp;socklen_t len = sizeof(tmp);ssize_t m = recvfrom(sockfd, buffer, sizeof(buffer)-1, 0, (struct sockaddr*)&tmp, &len);if(m>0){buffer[m] = '\0';std::cout<<"server echo# "<<buffer<<std::endl;}elsebreak;}elsebreak;}   close(sockfd);return 0;
}

客户机是先发出请求,再接收请求

运行效果如下

请添加图片描述

使用netstat -tuln可以查到服务器的ip地址和端口,当然这里只适合使用本机调试

相关文章:

Linux网络——socket编程与UDP实现服务器与客户机通信

文章目录 端口号TCP/UDP网络字节序socket的常见APIUDP实现服务器与客户机通信服务器客户机运行效果如下 端口号 我们说即便是计算机网络&#xff0c;他们之间的通信也仍然是进程间通信 那么要如何在这么多计算机中&#xff0c;找到你想要的那个进程呢 在网络中标识的唯一的计…...

大型语言模型中推理链的演绎验证

大语言模型&#xff08;LLMs&#xff09;在执行各种推理任务时&#xff0c;由于引入了链式推理&#xff08;Chain-of-Thought&#xff0c;CoT&#xff09;提示&#xff0c;显著受益。尽管CoT使模型产生更全面的推理过程&#xff0c;但其对中间推理步骤的强调可能会无意中引入幻…...

openharmony 应用支持常驻和自启动

本文环境: devEco studio 版本 4.0.0.600 SDK版本:3.2.12.5 full SDK 应用模型:Stage 功能简介: OpenHarmony支持包含ServiceExtensionAbility类型模块的应用配置常驻和自启动。 关于ServiceExtensionAbility其他的介绍可以参考官网:ServiceExtensionAbility(仅对…...

Winform中引入WPF控件后键盘输入无响应

引言 Winform中如何引入WPF控件的教程很多&#xff0c;对于我们直接通过ElementHost引入的直接显示控件&#xff0c;它是可以响应键盘输入消息的&#xff0c;但对于在WFP中弹出的窗体来说&#xff0c;此时是无法响应我们的键盘输入的。我们需要给它使能键盘输入。 1、使能键盘…...

多线程——死锁

死锁 在Java中使用多线程&#xff0c;就会有可能导致死锁问题。死锁会让程序一直卡住&#xff0c;程序不再往下执行。 我们只能通过中止并重启的方式来让程序重新执行。 这是我们非常不愿意看到的一种现象&#xff0c;我们要尽可能避免死锁的情况发生&#xff01; 死锁的原因…...

链路追踪可视化利器之火焰图

随着现代化技术的发展&#xff0c;为了能够保证 IT 系统的稳定性、高扩容性&#xff0c;企业往往采用分布式的方式来构建 IT 系统。但也正因为如此&#xff0c;IT 系统中涉及到的服务和组件可能被分布在不同的服务器、数据中心甚至不同的地理位置&#xff0c;这导致应用发生故障…...

C语言 ——— 条件编译指令实际用途

目录 前言 头文件被包含的方式 嵌套文件包含 使用条件编译指令规避头文件多次包含 还有一个编译指令&#xff0c;同样能做到以上功能 前言 条件编译指令多用于对头文件的定义和判断以及删除 头文件被包含的方式 本地文件包含&#xff08;也就是自己创建的头文件&#xff…...

备战软考Day01-计算机系统

1.数值及其转化 1.数值转化&#xff08;十进制&#xff09; 2.十进制推广 3.进制转化 4.数据表示 1.原码 2.反码 3.补码 4.移码 5.定点数 就是小数点的位置固定不变的数。小数点的位置通常有两种约定方式&#xff1a;定点整数(纯整数&#xff0c;小数点在最低有效数值位之后…...

从C语言过渡到C++

&#x1f4d4;个人主页&#x1f4da;&#xff1a;秋邱-CSDN博客☀️专属专栏✨&#xff1a;C &#x1f3c5;往期回顾&#x1f3c6;&#xff1a;单链表实现&#xff1a;从理论到代码-CSDN博客&#x1f31f;其他专栏&#x1f31f;&#xff1a;C语言_秋邱的博客-CSDN博客 目录 ​…...

Docker 的安装和使用

参考资料&#xff1a; 通俗易懂了解什么是docker?Docker 教程 | 菜鸟教程Ubuntu 22.04 安装 DockerDocker 超详细基础教程WSL2 支持 systemctl 命令systemd 和 systemctl 是什么&#xff1f;使用正确的命令重启 WSL 子系统Ubuntu 修改源镜像方法Docker 中出现 ‘/etc/resolv.…...

鸿蒙轻内核A核源码分析系列七 进程管理 (2)

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 轻内核A核源码分析系列一 数据结构-双向循环链表 轻内核A核源码分析系列二 数据结构-位图操作 轻内核A核源码分析系列三 物理内存&#xff08;1&#xff0…...

关于TypeScript使用讲解

TypeScript讲解 安装环境 1.安装node js 配置环境变量 2.在终端中 运行 npm i -g typescript typescript: 用于编译ts代码 提供了 tsc命令 实现了将 TS>>>> JS转换 验证: tsc -v 编译并运行 TS代码 1.创建ts文件&#xff08;TS文件为后缀名的文件&#xff0…...

C语言 | Leetcode C语言题解之第393题UTF-8编码验证

题目&#xff1a; 题解&#xff1a; static const int MASK1 1 << 7; static const int MASK2 (1 << 7) (1 << 6);bool isValid(int num) {return (num & MASK2) MASK1; }int getBytes(int num) {if ((num & MASK1) 0) {return 1;}int n 0;in…...

Netty权威指南:Netty总结-编解码与序列化

第四章 TCP粘包/拆包问题 4.1 TCP 粘包/拆包 TCP是流协议&#xff0c;也就是没有界限的的一串数据&#xff0c;底层并不知道上层业务数据的具体含义&#xff0c;也就是说一个完整的包可能会被拆分成多个包进行发送&#xff0c;也可能把几个小包封装成一个大的数据包发送。这就…...

FIDAVL:基于视觉语言模型的假图像检测与归因 !

FIDAVL:基于视觉语言模型的假图像检测与归因 &#xff01; 这份完整版的大模型 AI 学习资料已经上传CSDN&#xff0c;朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】 作者提出了FIDAVL&#xff1a;使用视觉语言模型进行虚假图像检测。FIDAVL是一…...

如何通过海外云手机提升运营效率

随着技术的不断进步&#xff0c;市场上出现了越来越多的提高跨国电商运营效率的应用&#xff0c;海外云手机就是其中一个。海外云手机的优势体现在多个方面&#xff0c;那么如何通过使用海外云手机来提升运营效率&#xff1f;可以从以下几个方面了解。 首先&#xff0c;海外云手…...

数据库4个范式的说明

在数据库设计中&#xff0c;范式&#xff08;Normal Form&#xff09;用于消除冗余和异常&#xff0c;确保数据一致性。以下是第一范式、第二范式、第三范式和BCNF&#xff08;Boyce-Codd Normal Form&#xff0c;即第四范式&#xff09;的示例说明&#xff1a; 1. 第一范式&a…...

Excel怎么截图?快速捕捉工作表的多种方法

大家好&#xff0c;这里是效率办公指南&#xff01; &#x1f4f8; 在日常工作中&#xff0c;我们经常需要对Excel工作表进行截图&#xff0c;无论是为了记录数据、制作演示还是进行数据对比。今天&#xff0c;我们就来学习几种在Excel中截图的方法以及它们的快捷键。 一、使…...

MyBatis动态SQL标签总结、开发手册、高阶用法(动态SQL、OGNL、批量操作、片段重用、 SQL 组合、 执行优化、嵌套查询与延迟加载)

MyBatis提供了一个非常强大的动态SQL功能&#xff0c;它使用了一组XML标签来帮助我们根据不同条件生成动态SQL。动态SQL的设计让开发者可以根据业务需求&#xff0c;灵活地构建SQL查询语句。以下是MyBatis动态SQL标签的总结。 动态SQL标签说明特点<if>条件判断语句&…...

出处不详 取数游戏

目录 取数游戏题目描述背景输入输出数据范围 题解解法优化 打赏 取数游戏 题目描述 背景 两人将 n n n个正整数围成一个圆环&#xff0c;规则如下&#xff1a; 第一名玩家随意选取数字&#xff1b;第二名玩家从与第一名玩家相邻的两个数字中选择一个&#xff1b;而后依次在…...

智慧医疗能源事业线深度画像分析(上)

引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动

一、前言说明 在2011版本的gb28181协议中&#xff0c;拉取视频流只要求udp方式&#xff0c;从2016开始要求新增支持tcp被动和tcp主动两种方式&#xff0c;udp理论上会丢包的&#xff0c;所以实际使用过程可能会出现画面花屏的情况&#xff0c;而tcp肯定不丢包&#xff0c;起码…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

Python爬虫(一):爬虫伪装

一、网站防爬机制概述 在当今互联网环境中&#xff0c;具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类&#xff1a; 身份验证机制&#xff1a;直接将未经授权的爬虫阻挡在外反爬技术体系&#xff1a;通过各种技术手段增加爬虫获取数据的难度…...

Pinocchio 库详解及其在足式机器人上的应用

Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库&#xff0c;专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性&#xff0c;并提供了一个通用的框架&…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行

项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战&#xff0c;克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...

解读《网络安全法》最新修订,把握网络安全新趋势

《网络安全法》自2017年施行以来&#xff0c;在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂&#xff0c;网络攻击、数据泄露等事件频发&#xff0c;现行法律已难以完全适应新的风险挑战。 2025年3月28日&#xff0c;国家网信办会同相关部门起草了《网络安全…...

基于Java+VUE+MariaDB实现(Web)仿小米商城

仿小米商城 环境安装 nodejs maven JDK11 运行 mvn clean install -DskipTestscd adminmvn spring-boot:runcd ../webmvn spring-boot:runcd ../xiaomi-store-admin-vuenpm installnpm run servecd ../xiaomi-store-vuenpm installnpm run serve 注意&#xff1a;运行前…...

探索Selenium:自动化测试的神奇钥匙

目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...

LCTF液晶可调谐滤波器在多光谱相机捕捉无人机目标检测中的作用

中达瑞和自2005年成立以来&#xff0c;一直在光谱成像领域深度钻研和发展&#xff0c;始终致力于研发高性能、高可靠性的光谱成像相机&#xff0c;为科研院校提供更优的产品和服务。在《低空背景下无人机目标的光谱特征研究及目标检测应用》这篇论文中提到中达瑞和 LCTF 作为多…...