网络(二)——套接字编程

文章目录

  • 理解源IP地址和目的IP地址
  • 认识端口号
  • 认识TCP/UDP协议
  • 网络字节序
  • socket编程接口
    • socket 常见API
    • sockaddr结构

理解源IP地址和目的IP地址

在IP数据包头部中, 有两个IP地址, 分别叫做源IP地址, 和目的IP地址;
源IP即发送方的地址,目的IP即接受方的地址;
但只有IP是不够的,完不成通信;
IP只能确认我们将信息发到哪一台机器上,但具体发给哪一个进程是不确定的;
因此,还需要有一个其他的标识来区分出,要发给哪个进程;

认识端口号

端口号(port)是传输层协议的内容

  • 端口号是一个2字节16位的整数
  • 端口号用来标识一个进程, 告诉操作系统, 当前的这个数据要交给哪一个进程来处理
  • IP地址 + 端口号能够标识网络上的某一台主机的某一个进程
  • 一个端口号只能被一个进程占用
IP表示目的地址
端口号(port)用来表示唯一一个服务的
IP + port可以标识全网唯一的服务

前面我们谈到PID表示唯一一个进程;此时端口号表示唯一一个进程;
它们之间有什么关系么?

一个进程可以绑定多个端口号;但是一个端口号不能被多个进程绑定;
端口号是传输层到应用层寻找服务时需要使用的字段,而进程的PID用于操作系统管理不同的进程;

认识TCP/UDP协议

TCP协议

  • 传输层协议
  • 有连接:通信前需要先建立连接
  • 可靠传输:TCP协议有一些措施来保证传输的可靠性
  • 面向字节流

UDP协议

  • 传输层协议
  • 无连接:通信前不需要建立连接
  • 不可靠传输:无措施来保证可靠性
  • 面向数据报

网络字节序

我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分, 网络数据流同样有大端小端之分. 那么如何定义网络数据流的地址呢?

  • 发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出;
  • 接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存;
  • 因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址.
  • TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节.
  • 不管这台主机是大端机还是小端机, 都会按照这个TCP/IP规定的网络字节序来发送/接收数据;
  • 如果当前发送主机是小端, 就需要先将数据转成大端; 否则就忽略, 直接发送即可;

在这里插入图片描述
调用以下库函数做网络字节序和主机字节序的转换

在这里插入图片描述
如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回;
如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回;

socket编程接口

socket 常见API

// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);// 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *address, socklen_t address_len);// 开始监听socket (TCP, 服务器)
int listen(int socket, int backlog);// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address, socklen_t* address_len);// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

sockaddr结构

套接字不仅支持跨网络的进程间通信,还支持本地的进程间通信(域间套接字)。在进行跨网络通信时我们需要传递的端口号和IP地址,而本地通信则不需要,因此套接字提供了sockaddr_in结构体和sockaddr_un结构体,其中sockaddr_in结构体是用于跨网络通信的,而sockaddr_un结构体是用于本地通信的。

为了让套接字的网络通信和本地通信能够使用同一套函数接口,于是就出现了sockeaddr结构体,该结构体与sockaddr_in和sockaddr_un的结构都不相同,但这三个结构体头部的16个比特位都是一样的,这个字段叫做协议家族。
在这里插入图片描述
此时当我们在传递在传参时,就不用传入sockeaddr_in或sockeaddr_un这样的结构体,而统一传入sockeaddr这样的结构体。在设置参数时就可以通过设置协议家族这个字段,来表明我们是要进行网络通信还是本地通信,在这些API内部就可以提取sockeaddr结构头部的16位进行识别,进而得出我们是要进行网络通信还是本地通信,然后执行对应的操作。此时我们就通过通用sockaddr结构,将套接字网络通信和本地通信的参数类型进行了统一。

实际我们在进行网络通信时,定义的还是sockaddr_in这样的结构体,只不过在传参时需要将该结构体的地址类型进行强转为sockaddr。
UdpServer

#pragma once#include <iostream>
#include <string>
#include <cerrno>
#include <cstring>
#include <unistd.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "nocopy.hpp"
#include "Log.hpp"
#include "Comm.hpp"
#include "InetAddr.hpp"const static uint16_t defaultport = 8888;
const static int defaultfd = -1;
const static int defaultsize = 1024;class UdpServer
{
public:UdpServer(uint16_t port = defaultport): _port(port), _sockfd(defaultfd){}void Init(){// 1. 创建socket,就是创建了文件_sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (_sockfd < 0){lg.LogMessage(Fatal, "socket errr, %d : %s\n", errno, strerror(errno));exit(Socket_Err);}lg.LogMessage(Info, "socket success, sockfd: %d\n", _sockfd);// 2. 绑定,指定网络信息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; // 0// 填写结构体int n = ::bind(_sockfd, (struct sockaddr *)&local, sizeof(local));if (n != 0){lg.LogMessage(Fatal, "bind errr, %d : %s\n", errno, strerror(errno));exit(Bind_Err);}}void Start(){// 服务器不退出char buffer[defaultsize];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:// std::string _ip;uint16_t _port;int _sockfd;
};

UdpClient

#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 &process)
{std::cout << "Usage: " << process << " server_ip server_port" << std::endl;
}// ./udp_client server_ip server_port
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]);// 1. 创建socketint sock = socket(AF_INET, SOCK_DGRAM, 0);if (sock < 0){std::cerr << "socket error: " << strerror(errno) << std::endl;return 2;}std::cout << "create socket success: " << sock << 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);// 我们要发给serverssize_t n = sendto(sock, inbuffer.c_str(), inbuffer.size(), 0, (struct sockaddr*)&server, sizeof(server));if(n > 0){char buffer[1024];//收消息struct sockaddr_in temp;socklen_t len = sizeof(temp);ssize_t m = recvfrom(sock, buffer, sizeof(buffer)-1, 0, (struct sockaddr*)&temp, &len); if(m > 0){buffer[m] = 0;std::cout << "server echo# " << buffer << std::endl;}elsebreak;}elsebreak;}close(sock);return 0;
}

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

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

相关文章

通信协议 | 一文玩转UART协议就够了

文章目录 协议基础1、UART简介2、UART特性3、UART协议帧3.1、起始位3.2、数据位3.3、奇偶校验位3.4、停止位 4、UART通信步骤 最详细的UART通讯协议分析Verilog代码实现UART接口模块驱动 协议基础 1、UART简介 UART&#xff08;Universal Asynchronous Receiver/Transmitter&…

express

文章目录 🟢 Express⭐️ 1.初始Express✨安装✨使用Express 搭建一台服务器⭐️2.Express-基本路由✨1.使用字符串模式的路由路径示例:✨2.使用正则表达式的路由路径示例:✨3.中间件浅试(demo)⭐️3.Express-中间件✨1.应用级中间件✨2.路由级中间件✨3.错误处理中间件✨4…

【pytorch】手写数字识别

https://blog.csdn.net/qq_45588019/article/details/120935828 基本均参考该博客 《深度学习原理Pytorch实战》 初步处理 导包 import torch import numpy as np from matplotlib import pyplot as plt from torch.utils.data import DataLoader from torchvision import tr…

同时用到,网页,java程序,数据库的web小应用

具体实现功能&#xff1a;通过网页传输添加用户的请求&#xff0c;需要通过JDBC来向 MySql 添加一个用户数据 第一步&#xff0c;部署所有需要用到的工具 IDEA(2021.1),Tomcat(9),谷歌浏览器&#xff0c;MySql,jdk(17) 第二步&#xff0c;创建java项目&#xff0c;提前部署数…

《梦醒蝶飞:释放Excel函数与公式的力量》12.2 DAVERAGE函数

第12章&#xff1a;数据库函数 第二节 12.2 DAVERAGE函数 12.2.1 简介 DAVERAGE函数是Excel中的一个数据库函数&#xff0c;用于计算数据库或数据表中特定条件下某字段的平均值。DAVERAGE函数在处理大规模数据、数据筛选和分析时非常有用。 12.2.2 语法 DAVERAGE(database…

Kithara与OpenCV (一)

Kithara使用 OpenCV 库 目录 Kithara使用 OpenCV 库简介需求和支持的环境构建 OpenCV 库使用 CMake 进行配置以与 Kithara 一起工作 使用 OpenCV 库设置项目运行 OpenCV 代码图像采集和 OpenCV自动并行化限制和局限性1.系统建议2.实时限制3.不支持的功能和缺失的功能4.显示 Ope…

排序-java(详解)

一&#xff0c;分类 主要的排序大致分为以下几类&#xff1a; 1&#xff0c;插入排序&#xff0c;又分为直接插入排序和希尔排序 2&#xff0c;选择排序&#xff0c;又分为选择排序和堆排序 3&#xff0c;交换排序&#xff0c;又分为冒泡排序和快速排序 4&#xff0c;归并…

219.贪心算法:柠檬水找零(力扣)

代码解决 class Solution { public:bool lemonadeChange(vector<int>& bills) {int num50, num100; // 初始化5美元和10美元的计数器for(int i0; i < bills.size(); i) // 遍历所有账单{if(bills[i]5) // 如果账单是5美元{num5; // 增加5美元的计数continue; // …

手撸俄罗斯方块(五)——游戏主题

手撸俄罗斯方块&#xff08;五&#xff09;——游戏主题 当确定游戏载体&#xff08;如控制台&#xff09;后&#xff0c;界面将呈现出来。但是游戏的背景色、方块的颜色、方框颜色都应该支持扩展。 当前游戏也是如此&#xff0c;引入了 Theme 的概念&#xff0c;支持主题的扩…

ubuntu使用kubeadm搭建k8s集群

一、卸载k8s kubeadm reset -f modprobe -r ipip lsmod rm -rf ~/.kube/# 自己选择性删除 坑点哦 rm -rf /etc/kubernetes/ rm -rf /etc/systemd/system/kubelet.service.d rm -rf /etc/systemd/system/kubelet.service rm -rf /usr/bin/kube* rm -rf /etc/cni rm -rf /opt/cn…

【常见开源库的二次开发】一文学懂CJSON

简介&#xff1a; JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式。它基于JavaScript的一个子集&#xff0c;但是JSON是独立于语言的&#xff0c;这意味着尽管JSON是由JavaScript语法衍生出来的&#xff0c;它可以被任何编程语言读取和生成…

自动驾驶(萝卜快跑)是毁灭出租司机工作机会的灾难?

引言 自动驾驶技术的飞速发展在全球范围内引发了广泛的讨论和担忧&#xff0c;特别是在中国&#xff0c;自动驾驶出租车服务“萝卜快跑”成为了热门话题。本文探讨自动驾驶对出租司机工作机会的影响&#xff0c;以及这种技术变革背后的社会经济因素。 自动驾驶的历史与现状 …

【深度学习】PyTorch深度学习笔记01-Overview

参考学习&#xff1a;B站视频【《PyTorch深度学习实践》完结合集】-刘二大人 ------------------------------------------------------------------------------------------------------- 1. 基于规则的深度学习 2. 经典的机器学习——手动提取一些简单的特征 3. 表示学习…

Qt下使用OpenCV的鼠标回调函数进行圆形/矩形/多边形的绘制

文章目录 前言一、设置imshow显示窗口二、绘制圆形三、绘制矩形四、绘制多边形五、示例完整代码总结 前言 本文主要讲述了在Qt下使用OpenCV的鼠标回调在OpenCV的namedWindow和imshow函数显示出来的界面上进行一些图形的绘制&#xff0c;并最终将绘制好的图形显示在QLabel上。示…

python开发prometheus exporter--用于hadoop-yarn监控

首先写python的exporter需要知道Prometheus提供4种类型Metrics 分别是&#xff1a;Counter, Gauge, Summary和Histogram * Counter可以增长&#xff0c;并且在程序重启的时候会被重设为0&#xff0c;常被用于任务个数&#xff0c;总处理时间&#xff0c;错误个数等只增不减的指…

GAMMA软件适配航天宏图一号多星干涉数据

文章目录 1.航天宏图一号 X-频段 多基雷达星座2.航天宏图算法人员小结3.双基成像与单基成像干涉处理区别 GAMMA软件是世界著名的瑞士GAMMA遥感公司开发的专门用于干涉雷达数据处理的全功能商业软件。作为业内标杆软件&#xff0c;被全球范围内的研究人员、公司和公共机构广泛使…

Vim使用教程

目录 引言1. Vim的基本概念1.1 模式1.2 启动和退出 2. 基础操作2.1 导航2.2 插入文本2.3 删除和复制2.4 查找和替换 3. 高级功能3.1 多文件编辑3.2 宏录制和执行3.3 使用插件3.4 自定义快捷键 4. Vim脚本和自定义配置4.1 基本配置4.2 编写Vim脚本 5. 实用技巧5.1 快速移动5.2 批…

MT6985(天玑9200)芯片性能参数_MTK联发科旗舰5G移动平台处理器

MT6985天玑 9200 旗舰移动平台拥有专业级影像、沉浸式游戏和先进移动显示技术&#xff0c;以及更快捷、覆盖更广的 5G 和 支持 Wi-Fi 7 连接&#xff0c;具有高性能、高能效、低功耗表现。率先采用 Armv9 性能核&#xff0c;全部支持纯 64 位应用&#xff0c;开启高能效架构设计…

IC后端设计中的shrink系数设置方法

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 在一些成熟的工艺节点通过shrink的方式(光照过程中缩小特征尺寸比例)得到了半节点,比如40nm从45nm shrink得到,28nm从32nm shrink得到,由于半节点的性能更优异,成本又低,漏电等不利因素也可以…

nginx正向代理和反向代理

nginx正向代理和反向代理 正向代理以及缓存配置 代理&#xff1a;客户端不再是直接访问服务器&#xff0c;通过代理服务器访问服务端。 正向代理&#xff1a;面向客户端&#xff0c;我们通过代理服务器的IP地址访问目标服务端。 服务端只知道代理服务器的地址&#xff0c;真…