以udp协议创建通信服务器

news2024/11/25 11:39:22

概念图

 创建服务器让A,B主机完成通信。

认识接口

socket

 返回值:套接字,你可以认为类似fd

参数:

  1. domain->:哪种套接字,常用AF_INET(网络套接字)、AF_LOCAL(本地套接字)
  2. type->:发送数据类型,常用 SOCK_DGRAM(以数据报式发送)
  3. protocol->:一般填0,自动推导类型或者IPPROTO_UDP、IPPROTO_TCP。

创建一个套接字,类似创建一个文件标识符fd。

先介绍些结构体类型

struct sockaddr
struct sockaddr_in
struct sockaddr_un

_in结构体中保存的是ip\port数据,而_un中保存的则是本地的数据

udp协议为了本地通信与网络通信同一套接口兼容,所以先将sockaddr_in/_un强转成sockaddr类型传入各个函数,在函数中判断前2个字节类型,来做本地通信或者网络通信。

bind

将套接字绑定,一般来说套接字绑定都是服务器才会绑定的,客户端一般给操作系统自动分配ip与端口的。

返回值:成功0,失败-1.设置错误码

参数:

  1. sockfd 需要绑定的套接字
  2. sockaddr包含了需要与套接字绑定的ip和端口号。
  3. addrlen该结构体长度。

recvfrom

用来接收数据的接收

返回值:实际接收数据的长度,-1失败

参数

  1. sockfd:将从该套接字的端口和ip中取得数据
  2. buff:输出型参数,将数据存放到buff中。
  3. len:buff的长度
  4. flags:以状态等待数据,一般填0,阻塞等待数据
  5. src_addr:发送方ip+port结构体数据,输出型参数
  6. 结构体数据长度

sendto

发送数据给某个主机

返回值:实际发送数据的个数,-1失败

参数

  1. sockfd:将发送方的ip+port发送给对方
  2. buff:输入型参数,将buff中数据发送给对方。
  3. len:buff的长度;
  4. flags:默认发送方式发送
  5. 接收方ip+port结构体数据,根据该参数寻找对于主机
  6. 结构体数据长度

sockaddr_in结构体配套函数

机器大小端的转换函数。h本地to转

以太网规定,网络传输数据一定是大端方式传输,所以我们的机器无论是大端还是小端,在网络中都会成为大端序列。

 当是为了人能看的明白,我们的ip地址一般都是以字符串的方式呈现,这样的方式我们称为点分十进制的方式。而且传入为了的ip地址可能需要改序列,所以一批接口出现了。

这些接口将字符串转为uint32_t或者将uint32_t转为字符串

代码

一份2个主机通过服务器可以聊天的代码

服务器代码:

server.hpp

#pragma once
#include <cstdio>
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Log.hpp"
#include <unordered_map>
using std::cin;
using std::cout;
using std::endl;

class udp_server
{
    typedef int socket_t;
    void ip_type()
    {
        cout << "ip:" << _ip << endl;
        if (_ip == "127.0.0.1")
        {
            cout << "#####本地测试#####" << endl;
        }
        else if (_ip.empty())
        {
            cout << "#####开放全部ip地址#####" << endl;
        }
        else
        {
            cout << "#####指定ip地址#####" << endl;
        }
    }
    void init_server()
    {
        _socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
        if (_socket < 0)
        {
            Log(FATAL, "socket get fail!!![%d][%s]\n", __LINE__, __TIME__);
            exit(1);
        }
        struct sockaddr_in ip_port;
        bzero(&ip_port, sizeof(ip_port));
        ip_port.sin_family = AF_INET;
        ip_port.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str());
        ip_port.sin_port = htons(_port);
        if (bind(_socket, (struct sockaddr *)&ip_port, sizeof(ip_port)) < 0)
        {
            Log(FATAL, "bind  fail!!![%d][%s]\n", __LINE__, __TIME__);
            exit(2);
        }
        Log(NORMAL, "udp init success!!![%d][%s]\n", __LINE__, __TIME__);
    }

public:
    udp_server(uint16_t port, std::string ip = "") : _ip(ip), _port(port) {}
    udp_server() {}

    void activate()
    {
        init_server();
        ip_type();
        while (1)
        {
            char buff[1024] = {0};
            // cout<<"buff size: "<<strlen(buff)<<endl;
            struct sockaddr_in client_ip_port;
            socklen_t len = sizeof(client_ip_port);
            //开始等待客户端

            ssize_t end = recvfrom(_socket, buff, sizeof(buff) - 1, 0, (struct sockaddr *)&client_ip_port, &len);
            char retbuff[1024]={0};
            // cout<<"buff size: "<<strlen(buff)<<endl;
            if (end >= 0)
            {
                buff[end] = '\0';
                printf("[%s:%d]clint say# %s\n", inet_ntoa(client_ip_port.sin_addr), ntohs(client_ip_port.sin_port), buff);
                sprintf(retbuff,"[%s:%d]clint say# %s", inet_ntoa(client_ip_port.sin_addr), ntohs(client_ip_port.sin_port), buff);
            }
            else
            {
                Log(WARINNG, "recvfrom Message have fail [%d][%s]\n", __LINE__, __TIME__);
            }
            //处理数据。
            char key[64];
            snprintf(key,sizeof(key),"%s-%u",inet_ntoa(client_ip_port.sin_addr),client_ip_port.sin_port);
            auto it = _users.find(key);
            if(it==_users.end())
            {
                cout<<key<<endl;
                cout<<key<<" :放入客户端"<<endl;
                _users.insert({key,client_ip_port});
            }

            // cout<<"end : "<<end<<endl;
            //反馈
            for(auto&it:_users)
            {
                if(client_ip_port.sin_addr.s_addr==it.second.sin_addr.s_addr)
                {
                    continue;
                }
                sendto(_socket, retbuff, sizeof retbuff, 0, (struct sockaddr *)&(it.second), sizeof(it.second));
            }
            Log(Debug, "sendto Message have fail [%d][%s]\n", __LINE__, __TIME__);
        }
    }

private:
    socket_t _socket;
    std::string _ip;
    uint16_t _port;
    std::unordered_map<std::string, struct sockaddr_in> _users;
};

server.cpp

#include "server.hpp"
#include <memory>
using std::shared_ptr;
void SERVERUER()
{
    std::cout<<"./server + ip + port"<<std::endl;
}


int main(int argc,char*argv[])
{
    if(argc==2||argc==3)
    {
        cout<<"argc:"<<argc<<endl;
        if(argc==2)
        {
            in_port_t port=atoi(argv[1]);
            shared_ptr<udp_server> server_ptr(new udp_server(port));
            server_ptr->activate();
        }
        else
        {
            
            in_port_t port=atoi(argv[2]);
            std::string ip=argv[1];
            shared_ptr<udp_server> server_ptr(new udp_server(port,ip));
            server_ptr->activate();
        }
    }
    else
    {
        SERVERUER();
    }
    return 0;
}

客户端代码

client.cpp

#include <cstdio>
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string>
#include <cstring>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Log.hpp"
#include <pthread.h>
using std::cin;
using std::cout;
using std::endl;
typedef int socket_t;

void CLIENTUER()
{
    std::cout << "./client + ip + port" << std::endl;
}

void *thread_func(void *ages)
{
    socket_t *_socket = (socket_t*)ages;
    char get_messages[102];
    struct sockaddr_in temp;
    bzero((void *)&temp, sizeof(temp));
    socklen_t len(sizeof temp);
    while (1)
    {
        ssize_t end = recvfrom(*_socket, get_messages, sizeof(get_messages) - 1, 0, (struct sockaddr *)&temp, &len);
        if (end >= 0)
        {
            get_messages[end] = 0;
            std::cout<< get_messages << std::endl;
        }
    }
    return nullptr;
}

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        CLIENTUER();
        exit(1);
    }
    socket_t _socket = socket(AF_INET, SOCK_DGRAM, 0);
    pthread_t tid;
    pthread_create(&tid,nullptr,thread_func,(void*)&_socket);
    std::string messages;
    struct sockaddr_in server_ip_port;
    bzero(&server_ip_port, sizeof(server_ip_port));
    server_ip_port.sin_family = AF_INET;
    server_ip_port.sin_addr.s_addr = inet_addr(argv[1]);
    server_ip_port.sin_port = htons(atoi(argv[2]));
    socklen_t len = sizeof(server_ip_port);

    while (1)
    {
        fflush(stdout);
        std::getline(std::cin, messages);
        sendto(_socket, messages.c_str(), messages.size(), 0, (struct sockaddr *)&server_ip_port, len);
    }
    return 0;
}

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

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

相关文章

sql 索引

如果表已经存在大量数据&#xff0c;突然需要插入大量数据&#xff0c;因为原来有索引结构&#xff0c;所以大批量数据写入&#xff0c;会导致维护索引&#xff0c;浪费资源。 可以先把表的索引删除&#xff0c;待数据插入完成&#xff0c;再创建索引。 这样可以节约资源和时间…

SAP物料分类账的简单理解

SAP物料分类账的简单理解 转自 SAP物料分类账的简单理解 - 知乎 一、SAP物料分类账理解 物料分类账&#xff0c;简称ML&#xff08;material ledger&#xff09;&#xff0c;其基本用途是可以用八个字概括“还原成本”、“还原库存”。即通过月底运行物料分类账&#xff0c;…

Docker修改容器ulimit的全部方案及各方案的详细步骤

要修改Docker容器的ulimit&#xff08;用户资源限制&#xff09;&#xff0c;有以下三种方案&#xff0c;每个方案的详细步骤如下&#xff1a; 方案一&#xff1a;在Dockerfile中设置ulimit 打开您的Dockerfile。在文件中添加以下命令来修改ulimit&#xff1a;RUN ulimit -n …

时空数据挖掘精选23篇论文解析【AAAI 2023】

今天和大家分享时空数据挖掘方向的资料。 时空数据挖掘是人工智能技术的重要分支&#xff0c;是一种采用人工智能和大数据技术对城市时空数据进行分析与挖掘的方法&#xff0c;旨在挖掘时空数据&#xff0c;理解城市本质&#xff0c;解决城市问题。 目前&#xff0c;时空数据…

世纪互联收入增长放缓,低于华尔街预期,全年业绩指引令投资者失望

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 全年业绩指引令投资者失望 世纪互联&#xff08;VNET&#xff09;在发布了第二季度喜忧参半的财务业绩后&#xff0c;依然坚持了此前发布的2023财年业绩指引。 财报显示&#xff0c;虽然世纪互联第二季度的收入同比增长了6…

谈判胜利!韩美合资厂平均薪资将提高25% | 百能云芯

据韩国时报报道&#xff0c;LG新能源与通用汽车在俄亥俄州成立的电动车电池公司Ultium Cells日前宣布&#xff0c;已与美国联合汽车工会&#xff08;UAW&#xff09;达成临时劳资协议&#xff0c;旨在将员工平均薪资提高25%。这一合作成为美国首个设有工会代表的电动车电池厂&a…

C# 使用SnsSharp实现文件拖拽功能

CSDN下载地址&#xff1a;https://download.csdn.net/download/sns1991sns/88041637 gitee下载地址&#xff1a;https://gitee.com/linsns/snssharp 技术优势&#xff1a; 不仅使用简单&#xff0c;还可解决由于系统管理权限问题导致的文件拖拽无响应问题。 使用举例&#x…

一篇文章全面解析Modbus协议

Modbus 协议是应用于电子控制器上的一种通用语言。通过此协议&#xff0c;控制器相互之间、控制器经由网络&#xff08;例如以太网&#xff09;和其它设备之间可以通信。它已经成为一通用工业标准。有了它&#xff0c;不同厂商生产的控制设备可以连成工业网络&#xff0c;进行集…

Postman接口自动化测试之——批量参数化(参数文件)

Postman接口请求中的参数引用格式&#xff1a;{{参数名}}参数文件只适用于集合中。 创建参数文件 以记事本举例&#xff0c;也可以使用其他编辑器&#xff1b;第一行参数名&#xff0c;用半角逗号&#xff08;英文逗号&#xff09;隔开&#xff0c;第二行为参数值&#xff0c…

nvm安装electron开发与编译环境

electron总是安装失败&#xff0c;下面说一下配置办法 下载软件 nvm npmmirror 镜像站 安装nvm 首先最好卸载node&#xff0c;不卸载的话&#xff0c;安装nvm会提示是否由其接管&#xff0c;保险起见还是卸载 下载win中的安装包 配置加速节点nvm node_mirror https://npmmi…

Postman API测试之道:不止于点击,更在于策略

引言&#xff1a;API测试的重要性 在当今的软件开发中&#xff0c;API已经成为了一个不可或缺的部分。它们是软件组件之间交互的桥梁&#xff0c;确保数据的流动和功能的实现。因此&#xff0c;对API的测试显得尤为重要&#xff0c;它不仅关乎功能的正确性&#xff0c;还涉及到…

<高阶数据结构>图

图 必要概念大致用途 存图邻接矩阵邻接表 遍历BFS(广度优先)DFS(深度优先) 最小生成树Kruskal算法Prim算法 寻最短路径Dijkstra算法 必要概念 图根据有无方向分为&#xff0c;有向图和无向图 组成&#xff1a;G (V, E) 顶点集合 V边的集合 E G(Graph),V(Vertex),E(Edge) 图可…

PHP环境配置

1.服务器 简单理解&#xff1a;服务器也是一台计算机&#xff0c;只是比平时用到的计算机在性能上更强大&#xff0c;开发中通常都需要将开发好的项目部署到服务器进行访问&#xff0c;例如&#xff1a;我们可以访问百度、淘宝、京东等&#xff0c;都是因为有服务器的存在&…

pip install bz2 和readline失败

python3.7.5 在跑模型时报错找不到bz2,使用pip install bz2 安装失败 bz2和readline应该是python自带的包 解决方案&#xff1a;重新编译安装python3.7.5,参考&#xff1a; https://www.hiascend.com/document/detail/zh/CANNCommunityEdition/70RC1alpha002/softwareinstall/…

E8267D 是德科技矢量信号发生器

描述 最先进的微波信号发生器 安捷伦E8267D PSG矢量信号发生器是业界首款集成式微波矢量信号发生器&#xff0c;I/Q调制最高可达44 GHz&#xff0c;典型输出功率为23 dBm&#xff0c;最高可达20 GHz&#xff0c;对于10 GHz信号&#xff0c;10 kHz偏移时的相位噪声为-120 dBc/…

C++ 深拷贝,浅拷贝

浅拷贝&#xff08;系统默认&#xff09;&#xff1a;单纯的值传递&#xff1b;即两个类对象&#xff0c;完全一样&#xff0c;值&#xff0c;堆空间等。所以如果释放两者之中的一个堆空间&#xff0c;那么另一个的堆空间也被释放。因为他们的堆空间是同一空间。 深拷贝&#x…

关于disriminative 和 generative这两种模型

但是&#xff0c;其实&#xff0c;根据李宏毅老师讲到的&#xff0c;generative model是做了一些假设的&#xff0c;比如&#xff0c;如果使用Naive Bayes的话&#xff0c;不同特征x1,x2...之间相互独立的话&#xff0c;其实是很容易出现较大的偏差的&#xff0c;因为不同特征变…

vscode使用anaconda自带的python环境在终端运行时报错

目录 具体报错内容官方翻译报错讲人话解决方法 具体报错内容 CommandNotFoundError: Your shell has not been properly configured to use conda activate. If your shell is Bash or a Bourne variant, enable conda for the current user with$ echo ". E:\Anaconda/e…

Android Gradle 同步优化

作者&#xff1a;究极逮虾户 很多人听到方法论三个字&#xff0c;就觉得我要开始pua&#xff0c;说我阿里味&#xff0c;但是我觉得这个查问题的方式可能会对大家有点帮助。 很多人都会有这样的困扰&#xff0c;给你的一个工作内容是一个你完全陌生的东西&#xff0c;第一选择…

补贴纷争,台积电欧洲计划引发格芯抗议 | 百能云芯

台积电近期海外布局计划引发了一系列反响。 继美国工会悍拒台积电加派台湾人力到亚利桑那厂进行支持&#xff0c;在德国设厂多年的芯片代工大厂格芯因不满德国对台积电在此设厂提供50亿欧元的巨额补贴&#xff0c;扬言将向欧盟提出申诉。 此外&#xff0c;台积电还有计划在日本…