第四章 Linux网络编程

ARP 协议

ARP 协议(Address Resolution Protocol)通过 IP 地址查找对应的 MAC 地址。
当一个主机需要发送数据给另一个主机时,它首先会检查本地的 ARP 缓存表(ARP cache)中是否存在目标主机的 MAC 地址。如果存在,则直接使用该 MAC 地址进行数据发送。如果不存在该 MAC 地址,则需要使用 ARP 协议来获取目标主机的 MAC 地址。
主机发送一个 ARP 请求消息(ARP Request)广播到局域网上的所有主机。该请求中包含了源主机的 MAC 地址、IP 地址以及目标主机的 IP 地址。其他主机收到该请求后,会检查自己的 IP 地址是否与目标主机的 IP 地址匹配。如果匹配,则认为是 ARP 请求的目标主机,并向源主机发送 ARP 响应消息(ARP Reply),其中包含了自己的 MAC 地址。源主机接收到 ARP 响应后,将目标主机的 IP 地址和 MAC 地址的映射关系存储在本地的 ARP 缓存表中,并使用目标主机的 MAC 地址进行数据发送。
通过这种方式,ARP 协议实现了通过 IP 地址查找对应的 MAC 地址,从而确保数据包能够正确地发送给目标主机。
字节序(用联合体判断大端小端)
/* 字节序:字节在内存中存储的顺序。小端字节序:数据的高位字节存储在内存的高位地址,低位字节存储在内存的低位地址大端字节序:数据的低位字节存储在内存的高位地址,高位字节存储在内存的低位地址
*/// 通过代码检测当前主机的字节序
#include <stdio.h>int main() {union {short value; // 2字节char bytes[sizeof(short)]; // char[2]} test;test.value = 0x0102;if((test.bytes[0] == 1) && (test.bytes[1] == 2)) {printf("大端字节序\n");} else if((test.bytes[0] == 2) && (test.bytes[1] == 1)) {printf("小端字节序\n");} else {printf("未知\n");}return 0;
}


字节序转换函数
/*
网络通信时,需要将主机字节序转换成网络字节序(大端),
另外一段获取到数据以后根据情况将网络字节序转换成主机字节序。// 转换端口
uint16_t htons(uint16_t hostshort); // 主机字节序 - 网络字节序
uint16_t ntohs(uint16_t netshort); // 主机字节序 - 网络字节序// 转IP
uint32_t htonl(uint32_t hostlong); // 主机字节序 - 网络字节序
uint32_t ntohl(uint32_t netlong); // 主机字节序 - 网络字节序
*/
#include <stdio.h>
#include <arpa/inet.h>int main() {// htons 转换端口unsigned short a = 0x0102;printf("a : %x\n", a);unsigned short b = htons(a);printf("b : %x\n", b);printf("=======================\n");// htonl 转换IPchar buf[4] = {192, 168, 1, 100};int num = *(int *)buf;int sum = htonl(num);unsigned char *p = (char *)∑printf("%d %d %d %d\n", *p, *(p+1), *(p+2), *(p+3));printf("=======================\n");// ntohlunsigned char buf1[4] = {1, 1, 168, 192};int num1 = *(int *)buf1;int sum1 = ntohl(num1);unsigned char *p1 = (unsigned char *)&sum1;printf("%d %d %d %d\n", *p1, *(p1+1), *(p1+2), *(p1+3));// ntohsreturn 0;
}


IP地址转换函数
#include <arpa/inet.h>
// p:点分十进制的IP字符串,n:表示network,网络字节序的整数
int inet_pton(int af, const char *src, void *dst);af:地址族: AF_INET AF_INET6src:需要转换的点分十进制的IP字符串dst:转换后的结果保存在这个里面// 将网络字节序的整数,转换成点分十进制的IP地址字符串
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);af:地址族: AF_INET AF_INET6src: 要转换的ip的整数的地址dst: 转换成IP地址字符串保存的地方size:第三个参数的大小(数组的大小)返回值:返回转换后的数据的地址(字符串),和 dst 是一样的
#include <stdio.h>
#include <arpa/inet.h>int main() {// 创建一个ip字符串,点分十进制的IP地址字符串char buf[] = "192.168.1.4";unsigned int num = 0;// 将点分十进制的IP字符串转换成网络字节序的整数inet_pton(AF_INET, buf, &num);unsigned char * p = (unsigned char *)#printf("%d %d %d %d\n", *p, *(p+1), *(p+2), *(p+3));// 将网络字节序的IP整数转换成点分十进制的IP字符串char ip[16] = "";const char * str = inet_ntop(AF_INET, &num, ip, 16);printf("str : %s\n", str);printf("ip : %s\n", str);printf("%d\n", ip == str);return 0;
}

TCP通信实现(服务器端)
// TCP 通信的服务器端#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>int main() {// 1.创建socket(用于监听的套接字)int lfd = socket(AF_INET, SOCK_STREAM, 0);if(lfd == -1) {perror("socket");exit(-1);}// 2.绑定struct sockaddr_in saddr;saddr.sin_family = AF_INET;// inet_pton(AF_INET, "192.168.193.128", saddr.sin_addr.s_addr);saddr.sin_addr.s_addr = INADDR_ANY; // 0.0.0.0saddr.sin_port = htons(9999);int ret = bind(lfd, (struct sockaddr *)&saddr, sizeof(saddr));if(ret == -1) {perror("bind");exit(-1);}// 3.监听ret = listen(lfd, 8);if(ret == -1) {perror("listen");exit(-1);}// 4.接收客户端连接struct sockaddr_in clientaddr;int len = sizeof(clientaddr);int cfd = accept(lfd, (struct sockaddr *)&clientaddr, &len);if(cfd == -1) {perror("accept");exit(-1);}// 输出客户端的信息char clientIP[16];inet_ntop(AF_INET, &clientaddr.sin_addr.s_addr, clientIP, sizeof(clientIP));unsigned short clientPort = ntohs(clientaddr.sin_port);printf("client ip is %s, port is %d\n", clientIP, clientPort);// 5.通信char recvBuf[1024] = {0};while(1) {// 获取客户端的数据int num = read(cfd, recvBuf, sizeof(recvBuf));if(num == -1) {perror("read");exit(-1);} else if(num > 0) {printf("recv client data : %s\n", recvBuf);} else if(num == 0) {// 表示客户端断开连接printf("clinet closed...");break;}char * data = "hello,i am server";// 给客户端发送数据write(cfd, data, strlen(data));}// 关闭文件描述符close(cfd);close(lfd);return 0;
}
TCP通信实现(客户端) client.c
// TCP通信的客户端
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>int main() {// 1.创建套接字int fd = socket(AF_INET, SOCK_STREAM, 0);if(fd == -1) {perror("socket");exit(-1);}// 2.连接服务器端struct sockaddr_in serveraddr;serveraddr.sin_family = AF_INET;inet_pton(AF_INET, "192.168.193.128", &serveraddr.sin_addr.s_addr);serveraddr.sin_port = htons(9999);int ret = connect(fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));if(ret == -1) {perror("connect");exit(-1);}// 3. 通信char recvBuf[1024];int i = 0;while(1) {sprintf(recvBuf, "data : %d\n", i++);// 给服务器端发送数据write(fd, recvBuf, strlen(recvBuf)+1);int len = read(fd, recvBuf, sizeof(recvBuf));if(len == -1) {perror("read");exit(-1);} else if(len > 0) {printf("recv server : %s\n", recvBuf);} else if(len == 0) {// 表示服务器端断开连接printf("server closed...");break;}sleep(1);}// 关闭连接close(fd);return 0;
}
server_process.c
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <wait.h>
#include <errno.h>void recyleChild(int arg) {while(1) {int ret = waitpid(-1, NULL, WNOHANG);if(ret == -1) {// 所有的子进程都回收了break;}else if(ret == 0) {// 还有子进程活着break;} else if(ret > 0){// 被回收了printf("子进程 %d 被回收了\n", ret);}}
}int main() {struct sigaction act;act.sa_flags = 0;sigemptyset(&act.sa_mask);act.sa_handler = recyleChild;// 注册信号捕捉sigaction(SIGCHLD, &act, NULL);// 创建socketint lfd = socket(PF_INET, SOCK_STREAM, 0);if(lfd == -1){perror("socket");exit(-1);}struct sockaddr_in saddr;saddr.sin_family = AF_INET;saddr.sin_port = htons(9999);saddr.sin_addr.s_addr = INADDR_ANY;// 绑定int ret = bind(lfd,(struct sockaddr *)&saddr, sizeof(saddr));if(ret == -1) {perror("bind");exit(-1);}// 监听ret = listen(lfd, 128);if(ret == -1) {perror("listen");exit(-1);}// 不断循环等待客户端连接while(1) {struct sockaddr_in cliaddr;int len = sizeof(cliaddr);// 接受连接int cfd = accept(lfd, (struct sockaddr*)&cliaddr, &len);if(cfd == -1) {if(errno == EINTR) {continue;}perror("accept");exit(-1);}// 每一个连接进来,创建一个子进程跟客户端通信pid_t pid = fork();if(pid == 0) {// 子进程// 获取客户端的信息char cliIp[16];inet_ntop(AF_INET, &cliaddr.sin_addr.s_addr, cliIp, sizeof(cliIp));unsigned short cliPort = ntohs(cliaddr.sin_port);printf("client ip is : %s, prot is %d\n", cliIp, cliPort);// 接收客户端发来的数据char recvBuf[1024];while(1) {int len = read(cfd, &recvBuf, sizeof(recvBuf));if(len == -1) {perror("read");exit(-1);}else if(len > 0) {printf("recv client : %s\n", recvBuf);} else if(len == 0) {printf("client closed....\n");break;}write(cfd, recvBuf, strlen(recvBuf) + 1);}close(cfd);exit(0); // 退出当前子进程}}close(lfd);return 0;
}
#include <iostream>
#include <fstream>
#include <string>
#include <list>
using namespace std;// 学生类
class Student {
private:string name;int regID;int score;public:Student(string name, int regID, int score) {this->name = name;this->regID = regID;this->score = score;}string getName() const {return name;}int getRegID() const {return regID;}int getScore() const {return score;}
};// HashMap类
class HashMap {
private:static const int SIZE = 10;list<Student*> hashTable[SIZE];int hashCode(int regID) {return regID % SIZE;}public:Student* get(int regID) {int index = hashCode(regID);for (Student* student : hashTable[index]) {if (student->getRegID() == regID) {return student;}}return nullptr;}bool put(Student* student) {int regID = student->getRegID();int index = hashCode(regID);for (Student* s : hashTable[index]) {if (s->getRegID() == regID) {return false; // 已存在相同学号的学生}}hashTable[index].push_back(student);return true;}
};int main() {HashMap studentMap;// 读取数据文件ifstream file("data.txt");if (file) {string line;while (getline(file, line)) {size_t pos1 = line.find(',');string name = line.substr(0, pos1);size_t pos2 = line.find(',', pos1 + 1);int regID = stoi(line.substr(pos1 + 1, pos2 - pos1 - 1));int score = stoi(line.substr(pos2 + 1));// 创建Student对象并添加到HashMap中Student* student = new Student(name, regID, score);studentMap.put(student);}file.close();// 输入学号,查询学生信息int regID;cout << "请输入学号:";cin >> regID;Student* student = studentMap.get(regID);if (student) {cout << "姓名:" << student->getName() << endl;cout << "学号:" << student->getRegID() << endl;cout << "成绩:" << student->getScore() << endl;} else {cout << "未找到该学号对应的学生信息" << endl;}} else {cout << "无法打开数据文件" << endl;}return 0;
}相关文章:
第四章 Linux网络编程
ARP 协议 ARP 协议(Address Resolution Protocol)通过 IP 地址查找对应的 MAC 地址。 当一个主机需要发送数据给另一个主机时,它首先会检查本地的 ARP 缓存表(ARP cache)中是否存在目标主机的 MAC 地址。如果存在&…...
无涯教程-JavaScript - OFFSET函数
描述 OFFSET函数返回对范围的引用,该范围是一个单元格或单元格范围中指定的行数和列数。 返回的引用可以是单个单元格或单元格范围。您可以指定要返回的行数和列数。 语法 OFFSET (reference, rows, cols, [height], [width]) 争论 Argument描述Required/OptionalReferenc…...
rust切片
切片类型写为[T]。 切片是序列的一个片段。 它是动态大小类型,所以要使用切片类型,就必须使用它的指针类型。引用是最常用的指针类型。 [T; n]能隐式转换成[T]。 一、定义切片 (一)不可变切片 &[T],共享切片&…...
2023/9/18 -- C++/QT
作业 完善登录框 点击登录按钮后,判断账号(admin)和密码(123456)是否一致,如果匹配失败,则弹出错误对话框,文本内容“账号密码不匹配,是否重新登录”,给定两…...
vue柱状图+折线图组合
<template><div id"main" style"width: 100%;height: 500px; padding-top: .6rem"></div> </template>data() {return {weekData: ["1周","2周","3周","4周","5周","6周&…...
js中如何实现一个简单的防抖函数?
聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 防抖函数⭐ 使用示例⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅!这个专栏是为那些对Web开发感兴趣、刚刚踏…...
mysq 主从同步错误之 Error_code 1032 handler error HA_ERR_KEY_NOT_FOUND
错误说明: MySQL主从同步的1032错误,一般是指要更改的数据不存在,SQL_THREAD提取的日志无法应用故报错,造成同步失败 (Update、Delete、Insert一条已经delete的数据)。 1032的错误本身对数据一致性没什么影…...
蓝桥杯 题库 简单 每日十题 day4
01 津津上初中了。妈妈认为津津应该更加用功学习,所以津津除了上学之外,还要参加妈妈为她报名的各科复习班。另外每周妈妈还会送她去学习朗诵、舞蹈和钢琴。但是津津如果一天上课超过八个小时就会不高兴,而且上得越久就会越不高兴。假设津津…...
l8-d21 域名解析与http服务器实现原理
一、域名解析gethostbyname函数 主机结构在 <netdb.h> 中定义如下: struct hostent { char *h_name; /* 官方域名 */ char **h_aliases; /* 别名*/ int h_addrtype; /* 地址族(地址类型) */ int h_l…...
网络安全(黑客技术)自学规划
一、什么是网络安全 网络安全可以基于攻击和防御视角来分类,我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术,而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 无论网络、Web、移动、桌面、云等哪个领域,都有攻与防两面性…...
阻止用邮件不停注册wordpress账户的方法
您可以使用多种不同的策略来阻止垃圾邮件注册。以下是一些策略供您参考:第1个最好用 1.完全禁用WordPress注册:如果您不需要在您的WordPress网站上公开注册,最好完全禁用注册,而不是试图打击垃圾邮件注册。要完全禁用WordPress上…...
低代码工具大比拼:哪个最适合你?
低代码开发平台正日益流行,成为企业和开发者们的首选。但是,面对市场上众多的低代码工具,你是否感到困惑呢?今天,就和数聚股份一起探讨一下,究竟应该选择哪个低代码工具才能最好地满足你的需求。 首先&…...
用Python实现链式调用
嗨喽,大家好呀~这里是爱看美女的茜茜呐 我们在使用Django的models查询数据库时,可以看到有这种写法: form app.models import XXX query XXX.objects.all() query query.filter(name123, age456).filter(salary999)在这种写法里面…...
基于SSM的汽车租赁后台管理系统
基于SSM的汽车租赁后台管理系统 介绍 包括登录、首页、客户管理、车辆管理、汽车出租、出租单管理、汽车入库、检查单管理、系统管理等功能,适合二次开发课程设计、毕业设计等 软件架构 SSM 运行环境 数据库 mysql 安装教程输入链接说明 端口:3306…...
Word 文档转换 PDF、图片
工作有需要 Word 文档转换 PDF、图片 的场景,我们来看看 Java 开发中怎么解决这个问题的。 Word 转 PDF Word 转 PDF 分为商用 Aspose 方案和开源 Apache POIiText 方案。 Aspose 方案 这种方式在目前来看应该是最好的,无论是转换的速度还是成功的概…...
解决Permission is not allowed后基于Ubuntu23.04安装配置docker与docker-compose
参考:Docker官网-Install Docker Engine on Ubuntu 一、 Install using the Apt repository 1.1 Set up Docker’s Apt repository 1.1.1 Add Docker’s official GPG key # Add Dockers official GPG key: sudo apt-get updatesudo apt-get install ca-certifi…...
[ABC118D] Match Matching
题目传送门 引 题目的描述很形象,梦回童年,注意一下火柴全部都用完 解法 显然 DP , 设计状态: f i : 用完 i 根木棒凑出的最大数 f_i:用完i根木棒凑出的最大数 fi:用完i根木棒凑出的最大数 状态转移: f i → f i c n t …...
程序员必须掌握哪些算法?
目录 简介1. 冒泡排序(Bubble Sort)思想 2. 快速排序(Quick Sort)思想 3. 二分查找(Binary Search)思想 4. 归并排序(Merge Sort)思想 5. 插入排序(Insertion Sort&#…...
Java高级之File类、节点流、缓冲流、转换流、标准I/O流、打印流、数据流
第13章 IO流 文章目录 一、File类的使用1.1、如何创建File类的实例1.2、常用方法1.2.1、File类的获取功能1.2.2、File类的重命名功能1.2.3、File类的判断功能1.2.4、File类的创建功能1.2.5、File类的删除功能 二、IO流原理及流的分类2.1、Java IO原理2.2、流的分类/体系结构 三…...
解决WSL2占用内存过多问题(Docker on WSL2: VmmemWSL)
解决WSL2占用内存过多问题(Docker on WSL2: VmmemWSL) 一、问题描述二、问题解决2.1 创建.wslconfig文件2.2 重启wsl2 一、问题描述 安装完WSL2后,又安装了Docker,使用了一段时间,发现电脑变卡,进一步查看…...
高效解决Visual C++运行库问题的终极方案实战指南
高效解决Visual C运行库问题的终极方案实战指南 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist Visual C运行库缺失或版本冲突是Windows开发者最常见的系统环境问…...
基于模型的测试在汽车行业的应用
作 者 | 路国光出 品 | 汽车电子与软件摘要:为解决汽车电子软件开发中传统测试效率低、覆盖不足、验证滞后等问题,本文以基于模型的系统工程(MBSE)为背景,研究基于模型的测试(MBT)在汽车行业的应…...
FPGA与CPLD在数字机顶盒中的关键技术应用
1. 可编程逻辑器件在数字机顶盒中的核心价值 数字机顶盒作为连接广播网络与终端显示设备的关键枢纽,其设计面临三大核心挑战:多标准兼容性、快速功能迭代和成本控制。Xilinx Spartan系列FPGA和CoolRunner CPLD通过硬件可重构特性,为这些挑战提…...
完整指南:3分钟解锁你的加密音乐文件
完整指南:3分钟解锁你的加密音乐文件 【免费下载链接】qmc-decoder Fastest & best convert qmc 2 mp3 | flac tools 项目地址: https://gitcode.com/gh_mirrors/qm/qmc-decoder 你是否曾经遇到过这样的情况:从音乐平台下载的歌曲只能在特定应…...
从零搭建私有化大语言模型服务器:Ollama、Docker与Open WebUI全栈指南
1. 项目概述:构建你自己的私有化大语言模型服务器如果你和我一样,对把个人数据交给云端AI服务商这件事始终心存疑虑,同时又渴望拥有一个功能完整、响应迅速、且完全掌控在自己手中的AI助手,那么搭建一个本地私有化的大语言模型&am…...
3分钟掌握B站缓存视频转换:m4s-converter让你的视频永久保存
3分钟掌握B站缓存视频转换:m4s-converter让你的视频永久保存 【免费下载链接】m4s-converter 一个跨平台小工具,将bilibili缓存的m4s格式音视频文件合并成mp4 项目地址: https://gitcode.com/gh_mirrors/m4/m4s-converter 你是否曾经遇到过这样的…...
工程人福音!一键提取图纸文字,告别手动打字
建筑工程施工管理工作中,涉及大量文书资料编制,涵盖施工组织设计、专项施工方案、各类报告文件、招投标技术标撰写、项目概况说明、工程量清单项目特征描述等诸多文字内容。此类资料编辑工作量大、耗时费力,人工录入不仅效率低下,…...
基于Ubuntu与Docker构建私有化文档协同平台:DzzOffice集成OnlyOffice实战
1. 为什么需要私有化文档协同平台 最近几年,越来越多的企业开始重视数据安全和隐私保护。我接触过不少中小企业客户,他们最头疼的问题就是:既想要像Google Docs那样的实时协作体验,又担心把商业文档存在第三方云平台的风险。这就是…...
【AI研发知识管理终极指南】:SITS2026权威框架首次深度解密,3大认知盲区正在拖垮你的AI工程化落地?
更多请点击: https://intelliparadigm.com 第一章:SITS2026框架的诞生背景与范式革命 传统智能系统开发长期受限于异构协议耦合、时序语义模糊及跨域协同低效三大瓶颈。2024年全球工业智能峰会(GIISS)发布的《智能时序系统白皮书…...
智能网联时代的分心驾驶:技术悖论、工程困境与系统化安全框架
1. 项目概述:一个被忽视的致命悖论 作为一名在汽车电子和智能网联领域摸爬滚打了十几年的工程师,我见过太多关于“未来出行”的炫酷概念和激动人心的技术路线图。从早期的车载信息娱乐系统,到后来的高级驾驶辅助系统,再到如今如火…...
