udp网络通信 socket

news2024/9/24 17:11:02

套接字是实现进程间通信的编程。IP可以标定主机在全网的唯一性,端口可以标定进程在主机的唯一性,那么socket通过IP+端口号就可以让两个在全网唯一标定的进程进行通信。

套接字有三种:

域间套接字:实现主机内部的进程通信的编程

原始套接字:使用网络层或者数据链路层的接口进行编程,更难更底层,例如制作抓包等网络工具

网络套接字:实现用户通信的编程

udp网络通信

服务端server

分析:

服务端最少需要有两个接口,一个用来初始化服务器,一个用来运行服务器

一:初始化服务器接口

创建socket,绑定端口

1.创建socket

socket接口

fedd87d5c4ed451a98cd741758e1fd65.png

第一个参数是域,用来确定通信类型27575ae93e4e46ccb56a96cff6bdffbb.png 

AF_UNIX就是域间套接字,AF_INET/AF_INET6是IPv4/IPv6的网络套接字

第二个参数是传输的数据种类 

1885a033313f4789a12b066d2b3a3cf2.png

最常用的是前两个,SOCK_STREAM是面向字节流(TCP),SOCK_DGRAM是面向数据报(UDP)

第三个参数传0即可,这里用不到 

0ddec27613af48f6ad4685f1ac6a541c.png

返回值返回一个文件描述符 

2.绑定端口

bind接口

1dac49aa4920483c96a1505b8fcbfff7.png

第一个参数是socket返回的文件描述符

第二个参数是一个包含通信属性的结构体,例如通信域,ip地址和端口号。这是一个输出型参数,而且不同的通信类型的结构体不一样,传参时要进行类型转换。

47ab09aafd6d47729a411520d3c0fba1.png

c84c77ee04cf4e0b821d436be4789ae2.png

sockaddr_in有三个成员需要我们初始化:
1.sin_family:通信域,网络通信使用AF_INET

这个成员使用了宏函数,宏传入参数sin_,所以sa_prefix##family等价于sin_family,它是一个无符号短整型

2.sin_port:端口号 

端口号会在网络间传输,需要对我们传入的端口号进行处理,使其符合网络字节序,要使用htons()接口

3.sin_addr:ip地址

这个成员是一个结构体,结构体内有一个无符号整形的成员。但是我们一般的ip地址是一个字符串例如(192.168.33.131),所以我们要先将字符串转化为数字,再将数字变为网络字节序。这要用到inet_addr(char*)接口

第三个参数时结构体大小,直接计算即可

注意:一般服务器bind的ip地址是0.0.0.0,如果一个服务是绑定到 0.0.0.0 ,那么外部机器访问该机器上所有 IP 都可以访问该服务。如果服务绑定到的是特定的 ip,则只有访问该 ip 才能访问到服务。

 初始化服务器代码样例:

class udpserver{
public:
    void init()
    {
        // 创建udp server
        sockfd_ = socket(AF_INET, SOCK_DGRAM, 0);
        if (sockfd_ < 0)
        {
            exit(1);
        }

        // bind socked
        //初始化结构体
        struct sockaddr_in local;
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);                  // 转化成网络字节序
        local.sin_addr.s_addr = inet_addr(ip_.c_str()); // 将ip转化成数字,再将数字转化为网络字节序
        //bind
        if (bind(sockfd_, (struct sockaddr *)&local, sizeof(local)) < 0)
        {
            exit(2);
        }

    }

    udpserver(uint16_t port = 8080, string ip = "0.0.0.0")
        : port_(port), ip_(ip)
    {
    }
    ~udpserver()
    {
        if (sockfd_ > 0)
            close(sockfd_);
    }
private:
    int sockfd_;
    uint16_t port_;
    string ip_;
};

二:运行服务器接口

接收数据,对数据做处理,最后发送数据

1.接收数据

recvfrom接口

c0a1d65b28404ddba7faec9ae3462b78.png

90acb0527a354fff915010617d47967d.png

第一个参数是socket返回的文件描述符,第二个是接收的数据存放的位置,第三个参数是buf空间的大小,第四个参数在本文中这里只要传0即可满足需求。

第五个参数是用来存储数据发送方(客户端)属性的结构体,第六个参数是结构体大小的指针

为什么要记录客户端的通信属性呢?因为服务端在对数据做处理后还要发送回客户端。 

 2.对数据做处理

需要根据实际需求进行处理,可以通过传函数指针,实现代码分层。见后面的代码示例。

3.发送数据

sendto接口

a2a60ee6474c46c883e5e79d428a34a5.png

5faa90bb08204028a1a991b756f61956.png

 第一个参数是socket的文件描述符,第二个参数是要发送的数据的地址,第三个参数是发送数据的大小,第四个参数传0。

第五个参数是数据接收方(客户端)属性的结构体,第六个参数是结构体大小。

运行服务器代码样例(包括前面的代码):

//udpserver.hpp
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>
using func = function<string(char*)>;
class udpserver{
public:
    void init()
    {
        // 创建udp server
        sockfd_ = socket(AF_INET, SOCK_DGRAM, 0);
        if (sockfd_ < 0)
        {
            exit(1);
        }

        // bind socked
        //初始化结构体
        struct sockaddr_in local;
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);                  // 转化成网络字节序
        local.sin_addr.s_addr = inet_addr(ip_.c_str()); // 将ip转化成数字,再将数字转化为网络字节序
        //bind
        if (bind(sockfd_, (struct sockaddr *)&local, sizeof(local)) < 0)
        {
            exit(2);
        }

    }

    void run(func fun)
    {
        char buf[1024] = {0};
        while (1)
        {
            struct sockaddr_in client; // 客户端的信息
            socklen_t len = sizeof(client);
            // 收数据
            ssize_t n = recvfrom(sockfd_, buf, sizeof(buf), 0, (struct sockaddr *)&client, &len);
            if (n < 0)
            {
                cout << "receice fail" << endl;
                continue;
            }
            buf[n] = 0;
            cout << "server get:" << buf << endl;
            // 处理数据,通过传递的函数实现数据处理的和网络通信解耦
            string ret = fun(buf);
            
            // 发送数据
            n = sendto(sockfd_, ret.c_str(), ret.size(), 0, (struct sockaddr *)&client, len);
        }
    }
    udpserver(uint16_t port = 8080, string ip = "0,0,0,0")
        : port_(port), ip_(ip)
    {
    }
    ~udpserver()
    {
        if (sockfd_ > 0)
            close(sockfd_);
    }
private:
    int sockfd_;
    uint16_t port_;
    string ip_;
};

//main.cpp
#include"udpserver.hpp"
#include<memory>

using namespace std;
string datagram(char* data)
{
    string ret = "Get message:";
    ret += data;
    return ret;
}
int main()
{
    unique_ptr<udpserver> server(new udpserver());
    server->init();
    server->run(datagram);
    return 0;
}

客户端client

分析:

客户端需要初始化客户端,发送数据,接收数据

一:初始化客户端

创建socket和服务端一样,不同的是客户端的bind是操作系统完成的不需要我们操作,客户端会在发送数据时由OS随机bind一个端口。因为客户端的设备可能同时请求多个服务端,例如手机会同时运行很多app,客户端的程序很难为服务端留一个固定的端口(不同公司之间开发软件不可能商量谁要用哪个客户端的端口),而且服务端没必要第一时间知道客户端的端口,客户端发送数据请求时可以获取到客户端的属性

二:发送数据

使用sendto()接口,和服务端一样。

三:接收数据

使用recvfrom()接口,和服务端一样。

客户端代码样例:

#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

using namespace std;
int main(int argc, char *argv[])
{
    //获取命令行参数,ip和端口号
    if(argc != 3)
    {
        cout << "Please input in this way" << endl;
        cout << "./udpclient" << " [ip]" << " [port]" << endl;
    }
    string ip = argv[1];
    uint16_t port = stoi(argv[2]);

    // 创建socket
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        cout << "client create fail" << endl;
    }
    //客户端不需要bind,但是客户端会在发送数据时由OS随机bind一个端口,因为客户端设备同时请求多个服务端,服务端很难让客户端的程序为其留一个固定的端口,而且没必要第一时间知道客户端的端口,客户端发送数据请求时可以获取到

    // 创建服务端信息的结构体
    struct sockaddr_in server;
    server.sin_port = htons(port);
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = inet_addr(ip.c_str());
    socklen_t len = sizeof(server);

    char buf[1024] = {0};
    string message;
    while (1)
    {
        // 发送数据
        cout << "Please Enter@";
        getline(cin, message);
        sendto(sockfd, message.c_str(), message.size(), 0, (struct sockaddr *)&server, len);

        // 接收数据
        struct sockaddr_in tem;
        socklen_t len_tem = sizeof(tem);
        ssize_t n = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&tem, &len_tem);
        if (n < 0)
        {
            cout << "client receive fail" << endl;
            continue;
        }
        buf[n] = 0;
        cout << buf << endl;
    }
}

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

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

相关文章

02 三数排序

题目&#xff1a; 代码&#xff1a; #include <stdlib.h> #include<stdio.h>void swap(int *x,int *y) {if(*x>*y){int temp*x;*x*y;*ytemp;} }int main() {int x,y,z;scanf("%d %d %d",&x,&y,&z);swap(&x,&y);swap(&y,&…

漏洞复现-赛蓝-企业管理系统

本文来自无问社区&#xff0c;更多漏洞复现可前往查看http://www.wwlib.cn/index.php/index 0x01 产品简介 赛蓝企业管理系统是一款为企业提供全面管理解决方案的软件系统&#xff0c;它能够帮助企业实现精细化管理&#xff0c;提高效率&#xff0c;降低成本。系统集成了多种…

XGBoost算法-代码实现和网格调参

目录 导包 特征工程 基本模型 超参数优化 导包 import pandas as pd import numpy as np import xgboost as xgb import pickle import sys import matplotlib.pyplot as plt from sklearn.metrics import make_scorer from sklearn.metrics import mean_absolute_error f…

什么是话费充值api接口?话费充值API接口如何对接?

话费充值 API 接口对接相关信息 对接方式 通过技术人员对接&#xff1a;会专门将自己的小程序或者 app 对接到充值平台&#xff0c;通过接口提交号码和金额进行充值&#xff0c;提交一笔订单充值一笔。 对接优势 高效完善&#xff1a;能够使得整个话费充值的流程便捷&#…

电信AEP平台WEB在线开发经验总结

目录 一、服务器环境搭建 二、Web应用服务器安装 三、tomcat的SSL证书部署 四、电信AEP平台WEB在线开发域名管理 五、效果展示 一、服务器环境搭建 首先得购买服务器&#xff0c;比如华为云、腾讯云的轻量应用服务器都可以。然后购买域名并进行ICP备案&#xff0c;最后对…

数据结构——顺序表中基本操作的实现

前言 该部分知识参考于《数据结构&#xff08;C语言版 第2版&#xff09;》24~28页 &#x1f308;每一个清晨&#xff0c;都是世界对你说的最温柔的早安&#xff1a;ૢ(≧▽≦)و✨ 注意 这里的ElemType是以Book类型的数据作为举例&#xff0c;如果需要更改可以自行改变&…

基于SpringBoot的古城墙景区管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于JavaSpringBootVueMySQL的古城墙景区管理系…

【C++题解】1275. 输出杨辉三角的前N行

欢迎关注本专栏《C从零基础到信奥赛入门级&#xff08;CSP-J&#xff09;》 问题&#xff1a;1275. 输出杨辉三角的前N行 类型&#xff1a;二维数组 题目描述&#xff1a; 输出杨辉三角的前 N 行( N<10 )。 输入&#xff1a; 输入只有一行&#xff0c;包括 1 个整数 N …

【Unity】【游戏开发】unity中快速导入VRM模型并应用动画

【背景】 之前介绍了不少通过Blender为中介,Match Rig应用Mixamo动画后导入Unity的方法。不过由于texture等的问题,这种方法有时显得效率太低,还需要自己改写材质的nodes,避免导入Unity后出现不适应。所以本篇寻求更高效的下载和导入VRM模型,Mixamo动画到Unity的方法。 …

2024 年 8 月区块链游戏研报:用户增长与加密货币市场波动并存

作者&#xff1a;Stella L (stellafootprint.network) 数据来源&#xff1a;Footprint Analytics Games Research 页面 8 月&#xff0c;加密货币市场面临严峻挑战&#xff0c;比特币和以太币的价值都大幅下跌。比特币下跌了 9.3%&#xff0c;而以太坊的跌幅更为严重&#x…

Resnet图像识别入门——池化层

前面的文章[Resnet图像识别入门——激活函数]介绍了3中常见的激活函数&#xff0c;以及激活函数在神经网络中的作用。 在CNN网络中&#xff0c;除了激活函数之外&#xff0c;还有一种算法也是很常见的&#xff0c;那就是池化层。在Resnet50中&#xff0c;就存在一个最大池化层…

VSCode GDB调试控制台只能查看变量不能执行调试命令的解决方案-var-create: unable to create variable object

背景 在使用VSCode进行GDB调试时&#xff0c;想使用x命令看一下某地址处的数值。然而&#xff0c;却给了报错而不显示&#xff1a; -var-create: unable to create variable object 这是啥原因呢&#xff1f; 解决方案 其实&#xff0c;在刚刚开始调试程序时&#xff0c;就以…

大数据Flink(一百一十四):PyFlink的作业开发入门案例

文章目录 PyFlink的作业开发入门案例 一、批处理的入门案例 1、示例 2、​​​​​​​​​​​​​​开发步骤 3、参考代码&#xff1a;基于DataStreamAPI编程 二、​​​​​​​​​​​​​​流处理的入门案例 1、​​​​​​​​​​​​​​示例 2、​​​​​…

2024年10款好用的文件加密软件!企业文件防泄密最佳选择

在数字化时代&#xff0c;数据安全已成为企业生存和发展的关键。随着企业数据量的不断增长&#xff0c;如何有效保护敏感信息免受未经授权的访问和泄露&#xff0c;成为企业面临的重要挑战。文件加密软件作为一种有效的数据保护工具&#xff0c;能够帮助企业确保数据的安全性和…

手机投屏到电脑怎么弄?

远程看看是一款免费的远程控制软件&#xff0c;它支持Windows、iOS和Android等多个系统&#xff0c;并且提供了文件传输、手机投屏、在线聊天等多种功能。我们可以使用远程看看软件进行手机投屏&#xff0c;从而帮助您的家人或朋友解决相应的手机问题。 1. 首先&#xff0c;将…

【运维方案】信息系统运维方案(Word完整版)

1 编制目的 2 系统运行维护 2.1 系统运维内容 2.2 日常运行维护方案 2.2.1 日常巡检 2.2.2 状态监控 2.2.3 系统优化 2.2.4 软件系统问题处理及升级 2.2.5 系统数据库管理维护 2.2.6 灾难恢复 2.3 应急运行维护方案 2.3.1 启动应急流程 2.3.2 成立应急小组 2.3.3 应急处理过程 …

如何给电脑设置静态IP地址:详细步骤与指南

在日常生活和工作中&#xff0c;我们经常需要使用电脑连接到网络。通常情况下&#xff0c;电脑会自动获取IP地址&#xff0c;但有时候&#xff0c;由于特定的网络需求或配置&#xff0c;我们可能需要手动为电脑设置静态IP地址。本文将详细介绍如何在Windows和Mac操作系统中为电…

操作系统 ---- 【2.3】进程控制

零、学习路线 一、什么是进程控制&#xff1f; 进程控制是进程管理中最基本的功能&#xff0c;主要包括创建新进程、终止已完成的进程、将因发生异常情况而无法继续运行的进程置于阻塞状态、负责进程运行中的状态转换等功能。如当一个正在执行的进程因等待某事件而暂时不能继续…

828华为云征文|docker部署overleaf搭建属于自己的论文编辑服务

1.介绍 1.1 什么是华为云Flexus X实例 最近华为云828 B2B企业节正在举办&#xff0c;Flexus X实例的促销也非常给力&#xff0c;大家可以去看看。特别是对算力性能有要求&#xff0c;同时对自建MySQL、Redis、Nginx性能有要求的小伙伴&#xff0c;千万不要错过。Flexus云服务器…

mysql datatime数据类型比实际多一秒问题

问题&#xff1a; 在项目上突然发现两个同一个Date时间存入数据库&#xff08;datetime类型&#xff09;和按照yyyy-MM-dd HH:mm:ss格式化时候有时候会相差一秒。 如下图&#xff1a; 格式为字符串为2024-09-10 14:18:41 存入数据库为2024-09-10 14:18:42 原因 SimpleDateF…