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

news2024/9/23 17:15:26

文章目录

  • 理解源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)); // memset
        local.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. 创建socket
    int 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);
        // 我们要发给server
        ssize_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;
            }
            else
                break;
        }
        else
            break;
    }

    close(sock);
    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[译] Rust标准库有些特殊,让我们改它

本篇是对 RustConf 2023中的The standard library is special. Let’s change that.这一视频的翻译与整理, 过程中为符合中文惯用表达有适当删改, 版权归原作者所有. 今天我将讨论Rust的标准库,更具体地说,是关于标准库有何特殊之处,以及为什么我们应该改变这一点。首先声明一下…

探索 Prompt 的世界:让你的 AI 更智能

探索 Prompt 的世界&#xff1a;让你的 AI 更智能 引言什么是 Prompt&#xff1f;Prompt 的重要性如何编写有效的 Prompt1. 清晰明确2. 包含关键细节3. 提供上下文 实践中的 Prompt 技巧1. 多次迭代2. 实验不同风格3. 结合实际应用 总结 引言 随着人工智能&#xff08;AI&…

通过vm可以访问那些属性——06

1.通过vue实例都可以访问那些属性&#xff1f;&#xff08;通过vm都可以vm.什么&#xff09; vue实例中的属性很多。有的以$开始&#xff0c;有的以_开始。 所有以$开始的属性&#xff0c;可以看做是公开的属性&#xff0c;这些属性是提供给程序员使用的 所有以_开始的属性&…

PyTorch是使用GPU和CPU优化的深度学习张量库——torchvision

torchvision datasets torchvision.datasets 包含了许多标准数据集的加载器。例如&#xff0c;CIFAR10 和 ImageFolder 是其中两个非常常用的类。 CIFAR10 CIFAR10 数据集是一个广泛使用的数据集&#xff0c;包含10类彩色图像&#xff0c;每类有6000张图像&#xff08;5000张…

<数据集>夜间车辆识别数据集<目标检测>

数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;5000张 标注数量(xml文件个数)&#xff1a;5000 标注数量(txt文件个数)&#xff1a;5000 标注类别数&#xff1a;8 标注类别名称&#xff1a;[car, pedestrian, traffic light, traffic sign, bicycle, bus, truck…

Leetcode(经典题)day2

H指数 274. H 指数 - 力扣&#xff08;LeetCode&#xff09; 先对数组排序&#xff0c;然后从大的一头开始遍历&#xff0c;只要数组当前的数比现在的h指数大就给h指数1&#xff0c;直到数组当前的数比现在的h指数小的时候结束&#xff0c;这时h的值就是要返回的结果。 排序…

Ubuntu搭建Android架构so库交叉编译环境

目录 前言一、下载NDK并安装二、安装NDK三、配置交叉编译工具链四、编写交叉编译脚本 前言 需要将一些源码编译成Android可用的架构的so库 一、下载NDK并安装 https://developer.android.google.cn/ndk/downloads/ 二、安装NDK 将下载下来的android-ndk-r23b-linux.zip解压…

17099 周工作计划安排

这个问题可以通过动态规划来解决。我们可以定义一个数组d&#xff0c;其中d[i]表示第i周选择项目后&#xff0c;产生的最大效益和。然后我们可以通过比较选择低压项目和高压项目的效益&#xff0c;来更新d[i]。 以下是解题步骤&#xff1a; 1. 初始化数组&#xff1a;首先&am…

《Linux系统编程篇》认识在linux上的文件 ——基础篇

前言 Linux系统编程的文件操作如同掌握了一把魔法钥匙&#xff0c;打开了无尽可能性的大门。在这个世界中&#xff0c;你需要了解文件描述符、文件权限、文件路径等基础知识&#xff0c;就像探险家需要了解地图和指南针一样。而了解这些基础知识&#xff0c;就像学会了魔法咒语…

视频播放器的问题

<template><div class"app-container"><el-form :model"queryParam" ref"queryForm" :inline"true"><el-form-item label"题目ID&#xff1a;"><el-input v-model"queryParam.id" cle…

python:绘制一元三次函数的曲线

编写 test_x3_3x.py 如下 # -*- coding: utf-8 -*- """ 绘制函数 y x^33x4 在 -3<x<3 的曲线 """ import numpy as np from matplotlib import pyplot as plt# 用于正常显示中文标题&#xff0c;负号 plt.rcParams[font.sans-serif] […

免费的AI抠图工具 毫秒级抠图 离线可用 -鲜艺AI抠图

鲜艺AI抠图是一款免费的AI抠图工具&#xff0c;不登录、不联网&#xff0c;内嵌 AI 模型&#xff0c;快至毫秒级抠图&#xff0c;支持批量抠图&#xff0c;支持点击按钮选择图片、拖入图片、粘贴图片、粘贴图片链接、从网页拖入图片&#xff0c;支持Windows和macos&#xff0c;…

Linux:Linux网络总结(附下载链接)

文章目录 下载链接网络问题综合问题访问一个网页的全过程&#xff1f;WebSocket HTTPHTTP基本概念GET与POSTHTTP特性HTTP缓存技术HTTP的演变HTTP1.1 优化 HTTPSHTTP与HTTPS有哪些区别&#xff1f;HTTPS解决了HTTP的哪些问题&#xff1f;HTTPS如何解决的&#xff1f;HTTPS是如何…

【触想智能】安卓工控一体机在自助终端设备上的应用分析

随着科技的发展和人们对自动化系统的需求不断增强&#xff0c;自助终端设备已经成为日常生活非常常见的设备之一&#xff0c;例如自助售货机、自助点餐机、自助银行服务等。这些设备在使用中都需要一个可靠的、稳定的操作系统来支持其各项功能的实现。 因此&#xff0c;安卓工控…

Postman接口模拟请求工具使用技巧

Postman是一款非常强大的接口模拟请求工具&#xff0c;可以帮助开发者快速测试、调试API接口。下面集合实际使用过程中的经验&#xff0c;分享大家一些基础使用技巧&#xff1a; 1. 安装与启动&#xff1a;首先在官网&#xff08;Download Postman | Get Started for Free&…

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

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

html(抽奖设计)

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>抽奖</title><style type"text/css">* {margin: 0;padding: 0;}.container {width: 800px;height: 800px;border: 1px dashed red;position: absolut…

【学习笔记】无人机(UAV)在3GPP系统中的增强支持(四)-无人机系统(UAS)命令与控制(C2)通信用例

引言 本文是3GPP TR 22.829 V17.1.0技术报告&#xff0c;专注于无人机&#xff08;UAV&#xff09;在3GPP系统中的增强支持。文章提出了多个无人机应用场景&#xff0c;分析了相应的能力要求&#xff0c;并建议了新的服务级别要求和关键性能指标&#xff08;KPIs&#xff09;。…

鸿蒙系统在服装RFID管理中的应用:打造智能零售新时代

​随着物联网技术的迅速发展&#xff0c;服装零售行业正面临着新的变革与挑战。鸿蒙系统作为新一代智能操作系统&#xff0c;结合RFID技术&#xff0c;为服装行业提供了高效、智能的管理解决方案。常达智能物联&#xff0c;作为RFID技术的领先企业&#xff0c;致力于将鸿蒙系统…

【学习笔记】无人机(UAV)在3GPP系统中的增强支持(五)-同时支持无人机和eMBB用户数据传输的用例

引言 本文是3GPP TR 22.829 V17.1.0技术报告&#xff0c;专注于无人机&#xff08;UAV&#xff09;在3GPP系统中的增强支持。文章提出了多个无人机应用场景&#xff0c;分析了相应的能力要求&#xff0c;并建议了新的服务级别要求和关键性能指标&#xff08;KPIs&#xff09;。…