计算机网络自顶向下(2)----socket编程

news2024/10/1 3:34:06

1.套接字

        套接字是用于在计算机网络中进行通信的一种技术。它是操作系统提供的一种接口,通过该接口,应用程序可以通过网络连接进行数据的传输和接收。

        套接字包含了一个IP地址和一个端口号,用于唯一标识一个网络连接。通过套接字,应用程序可以使用不同的协议(如TCP、UDP)进行数据的传输。

2.socket

        套接字(Socket)是一种编程接口,用于实现网络通信。它是操作系统提供的一种抽象,允许应用程序通过网络进行数据传输和接收。

        在网络编程中,套接字通常被称为 Socket。通过 Socket,应用程序可以通过网络连接到其他计算机并与其进行通信。Socket 提供了一种标准的编程接口,使得应用程序可以使用不同的协议(如 TCP、UDP)进行数据传输。

1.创建socket

int socket(int domain, int type, int protocol);
  • domain:指定地址家族,例如AF_INETAF_INET6
  • type:指定socket类型,例如SOCK_STREAM(用于TCP)或SOCK_DGRAM(用于UDP)。
  • protocol:通常设置为0,让系统选择type参数对应的默认协议。

2.绑定

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • sockfd:socket文件描述符。
  • addr:指向包含地址信息的sockaddr结构的指针。
  • addrlensockaddr结构的大小。

        在Linux网络编程中,recvfrom 是一个系统调用,用于从(已连接的或未连接的)socket接收数据。对于未连接的socket(例如UDP socket),recvfrom 允许接收来自任何发送者的数据,并返回发送者的地址信息。

#include <sys/socket.h>

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                 struct sockaddr *src_addr, socklen_t *addrlen);
  • sockfd:接收数据的socket文件描述符。
  • buf:指向缓冲区的指针,该缓冲区用于存储接收到的数据。
  • len:缓冲区的大小,即要接收的最大数据量。
  • flags:指定调用行为的标志,例如 MSG_DONTWAIT(非阻塞操作)或 MSG_PEEK(查看数据但不从缓冲区中移除)。
  • src_addr:指向 sockaddr 结构的指针,该结构用于存储发送者的地址信息。如果不需要此信息,可以设置为 NULL
  • addrlen:指向 socklen_t 类型的指针,它初始化为 src_addr 结构的大小。在调用返回时,addrlen 被设置为实际存储在 src_addr 中的地址的大小。

  sendto 是Linux网络编程中的一个系统调用,用于向一个指定的地址发送数据。这个系统调用通常用于UDP协议,因为UDP是无连接的,所以需要在每次发送数据时指定目标地址。对于TCP协议,由于它是面向连接的,所以通常使用 send 或 write 系统调用来发送数据。

#include <sys/socket.h>

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
               const struct sockaddr *dest_addr, socklen_t addrlen);
#pragma once

#include <iostream>
#include <string>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "Log.hpp"
#include "InetAddr.hpp"

// echo server -> client -> server
enum
{
    SOCKET_ERROR = 1,
    BIND_ERROR,
    USAGE_ERROR
};

const static int defaultfd = -1;

class UdpServer
{
public:
    UdpServer(uint16_t port) : _sockfd(defaultfd), _port(port), _isrunning(false)
    {
    }
    void InitServer()
    {
        // 1. 创建udp socket 套接字 --- 必须要做的
        _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if (_sockfd < 0)
        {
            LOG(FATAL, "socket error, %s, %d\n", strerror(errno), errno);
            exit(SOCKET_ERROR);
        }
        LOG(INFO, "socket create success, sockfd: %d\n", _sockfd);

        // 2.0 填充sockaddr_in结构
        struct sockaddr_in local; // struct sockaddr_in 系统提供的数据类型。local是变量,用户栈上开辟空间。int a = 100; a = 20;
        bzero(&local, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port); // port要经过网络传输给对面,先到网络,_port:主机序列-> 主机序列,转成网络序列
        // a. 字符串风格的点分十进制的IP地址转成 4 字节IP
        // b. 主机序列,转成网络序列
        // in_addr_t inet_addr(const char *cp) -> 同时完成 a & b
        // local.sin_addr.s_addr = inet_addr(_ip.c_str()); // "192.168.3.1" -> 字符串风格的点分十进制的IP地址 -> 4字节IP
        local.sin_addr.s_addr = INADDR_ANY; // htonl(INADDR_ANY);

        // 2.1 bind sockfd和网络信息(IP(?) + Port)
        int n = bind(_sockfd, (struct sockaddr *)&local, sizeof(local));
        if (n < 0)
        {
            LOG(FATAL, "bind error, %s, %d\n", strerror(errno), errno);
            exit(BIND_ERROR);
        }
        LOG(INFO, "socket bind success\n");
    }
    void Start()
    {
        // 一直运行,直到管理者不想运行了, 服务器都是死循环
        // UDP是面向数据报的协议
        _isrunning = true;
        while (true)
        {
            char buffer[1024];
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer); // 必须初始化成为sizeof(peer)
            // 1. 我们要让server先收数据
            ssize_t n = recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len);
            if (n > 0)
            {
                buffer[n] = 0;
                InetAddr addr(peer);
                LOG(DEBUG, "get message from [%s:%d]: %s\n", addr.Ip().c_str(), addr.Port(), buffer);
                // 2. 我们要将server收到的数据,发回给对方
                sendto(_sockfd, buffer, strlen(buffer), 0, (struct sockaddr *)&peer, len);
            }
        }
        _isrunning = false;
    }
    ~UdpServer()
    {
    }

private:
    int _sockfd;
    // std::string _ip; // 暂时这样写,这个地方不是必须的.TODO
    uint16_t _port;  // 服务器所用的端口号
    bool _isrunning;
};
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

void Usage(std::string proc)
{
    std::cout << "Usage:\n\t" << proc << " serverip serverport\n"
              << std::endl;
}

// ./udpclient serverip serverport
int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        Usage(argv[0]);
        exit(1);
    }
    std::string serverip = argv[1];
    uint16_t serverport = std::stoi(argv[2]);

    // 1. 创建socket
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sockfd < 0)
    {
        std::cerr << "socket error" << std::endl;
    }
    // 2. client要不要bind?一定要,client也要有自己的IP和PORT。要不要显式[和server一样用bind函数]的bind?不能!不建议!!
    // a. 如何bind呢?udp client首次发送数据的时候,OS会自己自动随机的给client进行bind --- 为什么?防止client port冲突。要bind,必然要和port关联!
    // b. 什么时候bind呢?首次发送数据的时候

    // 构建目标主机的socket信息
    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());

    std::string message;
    // 2. 直接通信即可
    while(true)
    {
        std::cout << "Please Enter# ";
        std::getline(std::cin, message);
        sendto(sockfd, message.c_str(), message.size(), 0, (struct sockaddr*)&server, sizeof(server));

        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        char buffer[1024];
        ssize_t n = recvfrom(sockfd, buffer, sizeof(buffer)-1, 0, (struct sockaddr*)&peer, &len);
        if(n > 0)
        {
            buffer[n] = 0;
            std::cout << "server echo# " << buffer << std::endl;
        }
    }
    return 0;
}
#include <iostream>
#include <memory>
#include "UdpServer.hpp"

        
void Usage(std::string proc)
{
    std::cout << "Usage:\n\t" << proc << " local_port\n" << std::endl;
}

// ./udpserver port
// 云服务器的port默认都是禁止访问的。云服务器放开端口8080 ~ 8085
int main(int argc, char *argv[])
{
    if(argc != 2)
    {
        Usage(argv[0]);
        exit(USAGE_ERROR);
    }
    EnableScreen();
    // std::string ip = argv[1]; // TODO
    uint16_t port = std::stoi(argv[1]);
    std::unique_ptr<UdpServer> usvr = std::make_unique<UdpServer>(port); // C++14
    usvr->InitServer();
    usvr->Start();

    return 0;
}

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

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

相关文章

详解Linux文件系统

先来研究一下磁盘&#xff1a; LBA 磁头面数 所有磁头是共进退的。 每个扇区的大小假设为&#xff1a;512 磁盘的总容量&#xff1a;盘面*t*s*512 数组的下标范围&#xff1a;盘面*t*s LBA&#xff1a;xxx 假设xxx为LBA地址 xxx/1000h 及为h号盘面 xxx/100c 及c号磁道…

国产化框架PaddleYOLO结合Swanlab进行作物检测

1. 项目介绍 粮食安全&#xff0c;作为人类生存与发展的基石&#xff0c;始终是全球关注的焦点。它不仅仅关乎粮食的充足供应&#xff0c;更涉及粮食的质量安全、营养健康以及可持续生产等多个维度。在全球化、气候变化和资源环境约束日益加剧的背景下&#xff0c;如何确保粮食…

ComfyUI物品移除讲解

实现效果 一、下载插件 comfyui inpaint nodes 提供重绘功能节点&#xff0c;效果比自带的好很多 官方介绍 使用ComfyUI更好地进行修补的节点&#xff1a;用于SDXL&#xff0c;LaMa&#xff0c;MAT和各种其他工具的Foocus修补模型&#xff0c;用于预填充修补和去除区域。 插件…

Android调用科大讯飞语音转写 API以及解析踩坑之旅

需求 需要对本地音频文件&#xff0c;调用科大讯飞的api进行转文字&#xff0c;本来呢&#xff0c;以为很简单&#xff0c;结果坑不少。 语音转写 API 文档 坑1&#xff1a;解析 下载demo&#xff0c;代码也挺简单&#xff0c;放到idea中&#xff0c;替换一下key&#xff0c…

基于Springboot+Vue的网上书店(含源码数据库)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 在这个…

用户体验测试——21条UX设计原则

根据心理学的研究和发展,对应理论不断被完善到用户体验设计领域,以下21条UX设计原则即为心理学在用户体验设计中的应用,在设计和测试中应用这些原则,可以提高用户体验质量特性,如下所示: 21条UX设计原则 有效性 特斯勒定律(最小复杂度定律) 这个定律也被称为“复杂性…

数据转换新利器,开启企业高效之路

Maria是 S 公司的采购专员&#xff0c;最近需要进行公司设备的采购&#xff0c;这可让她犯了难&#xff1a;公司多个部门提交采购申请&#xff0c;但每个部门都有着不同的需求。一时间她就收到了大量的申请单&#xff0c;却难以高效整合处理&#xff08;比如哪些申请可以合并采…

环境变量

见一见环境变量&#xff1a; 查看环境变量的命令 命令行&#xff1a; echo &PATH echo &HOME env ps ajx ps aux ps -f -o pid code.c中获取环境变量 main&#xff08;char* env[]&#xff09; char* getenv&#xff08;env_name&#xff09; 本地变量 shell…

App模拟下载场景的demo

摘要 目的&#xff1a;提供一个稳定的下载场景&#xff0c;可以手动触发和定时触发下载&#xff0c;每次下载相同大小文件&#xff0c;研究下载场景的功耗影响 原理&#xff1a;把电脑当做服务器&#xff0c;手机测试App固定下载电脑存放的某个XXXMB的大文件&#xff0c;基于…

如何使用ssm实现校园体育赛事管理系统的设计与实现+vue

TOC ssm713校园体育赛事管理系统的设计与实现vue 绪论 课题背景 身处网络时代&#xff0c;随着网络系统体系发展的不断成熟和完善&#xff0c;人们的生活也随之发生了很大的变化。目前&#xff0c;人们在追求较高物质生活的同时&#xff0c;也在想着如何使自身的精神内涵得…

PE节表中是否存在misc.VirtualSize 比SizeofRawData还要大的情况

确实是存在的,这是win10自带记事本,可以看到 确实是大.所以在申请imagebuffer的时候,还是需要比较大小.但是在还原的时候.只考虑sizeofRawData即可>

【Android 14源码分析】WMS-窗口显示-第一步:addWindow

忽然有一天&#xff0c;我想要做一件事&#xff1a;去代码中去验证那些曾经被“灌输”的理论。                                                                                  – 服装…

项目管理专业资质认证ICB 3中关于项目经理素质的标准

项目管理专业资质认证ICB 3中关于项目经理素质的标准&#xff0c;的确很全面&#xff0c;下面摘录之&#xff1a;

三款专业的英文文献翻译工具,翻译论文不在话下

阅读英文论文文献时免不了要借用一些翻译软件来帮助理解&#xff0c;但因为论文文献的特殊性&#xff0c;普通的翻译软件不能很好的翻译一些专业名词和术语&#xff0c;所以这里给大家分享三款可以胜任文献翻译的专业翻译工具&#xff0c;可以快速准确的完成英文文献翻译工作。…

CDGA|2024年数据治理的六个关键建议

随着数字经济的快速发展&#xff0c;数据已成为企业运营和决策的核心资产。在2024年&#xff0c;做好数据治理对于提升企业的竞争力和运营效率至关重要。以下是六个关键建议&#xff0c;帮助企业有效应对数据治理的挑战。 1. 制定明确的数据治理策略 首先&#xff0c;企业需要…

遥感影像-实例分割数据集:iSAID 从切图到YOLO格式数据集制作详细介绍

背景介绍 开源数据集isaid标注包含实例分割&#xff0c;但是原始影像太大&#xff0c;很吃显存&#xff0c;一般显卡无法用原始影像直接训练&#xff0c;所以需要对影像进行裁剪&#xff0c;并生成对应的标签&#xff0c;因为想用yolo系列跑模型&#xff0c;所以将标签需要转为…

【设计模式-模板】

定义 模板方法模式是一种行为设计模式&#xff0c;它在一个方法中定义了一个算法的骨架&#xff0c;并将一些步骤延迟到子类中实现。通过这种方式&#xff0c;模板方法允许子类在不改变算法结构的情况下重新定义算法中的某些特定步骤。 UML图 组成角色 AbstractClass&#x…

Java 为什么使用 UTF-16 而不是更节省内存的 UTF-8?

Java 选择 UTF-16 编码而不是更节省内存的 UTF-8 这一决定&#xff0c;涉及多个层面的设计权衡&#xff0c;包括历史原因、虚拟机&#xff08;JVM&#xff09;实现的复杂度、性能和字符处理的一致性。要理解这个问题&#xff0c;我们需要从 Java 语言的设计初衷、JVM 的工作机制…

C++:笔试题

1.什么是虚函数&#xff1f;什么是纯虚函数&#xff1f; 虚函数是类中的一个成员函数&#xff0c;使用关键字virtual在函数名前声明。 虚函数主要目的是允许子类重写父类中的同名函数&#xff0c;从而实现多态性&#xff0c;并且子函数重写的是虚函数表中的函数。 当通过父类的…

七、添加攻击音效

一、添加动画事件 1、在动画事件中添加音效 2、添加音频组件 3、代码 public void PlayAttackSound() {AudioSource1.PlayOneShot(AudioClip1, SoundValue);//PlayOneShot播放一个音频剪辑&#xff08;AudioClip&#xff09;一次 }