网络套接字补充——UDP网络编程

news2024/9/22 10:08:40

五、UDP网络编程

​ 1.对于服务器使用智能指针维护生命周期;2.创建UDP套接字;3.绑定端口号,包括设置服务器端口号和IP地址,端口号一般是2字节使用uint16_t,而IP地址用户习惯使用点分十进制格式所以传入的是string类型,同时要保证网络字节序列;4.执行run;

5.1使用接口

5.1.1创建套接字
int socket(int domain, int type, int protocol);
//第一个参数为域/协议家族AF_UNIX, AF_LOCAL表示域间套接字,AF_INET ,AF_INET6表示网络套接字,AF_PACKET表示原始套接字,除了AF开头也可以PF开头;
//第二个参数表示socket的类型SOCK_STREAM表示流式套接字,SOCK_DGRAM表示数据包套接字;
//第三个参数如果只有一个协议则使用0;
//返回值是socket文件的文件描述符,打开的是网卡设备;

在这里插入图片描述

在这里插入图片描述

5.1.2进行绑定
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr,
         socklen_t addrlen);
struct sockaddr {
    sa_family_t sa_family;
    char        sa_data[14];
}
//第一个参数是创建好的套接字文件描述符;
//第二个参数是输入型参数,一个特定的结构需要使用其他结构进行强转;
//第三个参数特定类型的长度
//返回值成功为0失败为-1,错误码被设置;
#include <strings.h>
void bzero(void *s, size_t n);
#include <string.h>
void *memset(void *s, int c, size_t n);
//使用上述函数进行清空
typedef uint16_t in_port_t;
typedef uint32_t in_addr_t;
struct in_addr
{
    in_addr_t s_addr;
};
typedef unsigned short int sa_family_t;
#define	__SOCKADDR_COMMON(sa_prefix) \
  sa_family_t sa_prefix##family
struct sockaddr_in
{
    __SOCKADDR_COMMON (sin_);
    in_port_t sin_port;			/* Port number.  */
    struct in_addr sin_addr;		/* Internet address.  */

    /* Pad to size of `struct sockaddr'.  */
    unsigned char sin_zero[sizeof (struct sockaddr) -
                           __SOCKADDR_COMMON_SIZE -
                           sizeof (in_port_t) -
                           sizeof (struct in_addr)];
};
sockaddr_in结构中,sin表示socket inet
sin_zero表示填充字段
sin_port表示端口号字段
sin_family表示使用的协议家族如AF_INET之类的
sin_addr表示的是IP地址结构
//local.sin_addr.s_addr = INADDR_ANY;//任意地址绑定
//字符串转整数接口
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int inet_aton(const char *cp, struct in_addr *inp);
in_addr_t inet_addr(const char *cp);//将字符串转32位并且是网络序列的;
//整数转字符串
char *inet_ntoa(struct in_addr in);//将整数转为字符串并且将网络字节序转为主机字节序
5.1.3数据报的读取
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                 struct sockaddr *src_addr, socklen_t *addrlen);
//第四个参数默认使用0以阻塞方式
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
5.1.4数据报的发送
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
               const struct sockaddr *dest_addr, socklen_t addrlen);

5.2补充知识

1.查看网络状态

netstat -nlupa
#查看网络状态,n表示能显示成数字的就都显示成数字,l表示listen u表示udp,p表示进程,a表示所有;

2.IP问题

​ 云服务器禁止直接绑定公网IP;配置较高的机器IP地址不唯一;只是绑定一个IP地址就会导致另一个IP地址的发往另一个IP地址的数据无法被接收;一般使用的是0,这样凡是发送给本主机的数据都要根据端口号向上交付,而不是先确定IP;即IP地址使用0表示的是任意地址绑定;

3.端口号问题

​ 云服务器端口号默认0-1023是不允许绑定的,是系统内定的端口号,一般由固定的应用层协议使用如,http-80,https-443,MySQL-3306,普通用户直接使用的一般是1024以后的端口号,端口号的范围是0-65535,可以在这个范围内使用;

​ 服务器需要绑定显式端口号但是客户端不需要显式绑定,操作系统会随机绑定;因为一个端口号只能被一个进程绑定,所以重复绑定同一个端口号会出错;防止出现这种冲突,就不允许用户显示绑定而是交给了操作系统,只要保证端口号的唯一性就可以,这样就不会导致不同软件的客户端出现绑定端口号冲突;一般服务器需要显示绑定端口号是因为一般是客户端先发送的请求,所以需要知道服务端的IP地址和端口号,且端口号不能发生变化必须是固定的,这样才能让客户端知道要发送的另一端进程是谁;

​ 系统会在客户端首次发送数据的时候进行端口号的绑定;客户端可以获取多个服务器的信息所以获取信息时要包含服务端的信息;

4.本地环回地址

​ 127.0.0.1是本地环回地址,通常来进行cs的测试;

5.3echo服务器实现

服务端

#include <sys/types.h>
#include <sys/socket.h>
#include "log.hpp"
#include <string>
#include <arpa/inet.h>
#include <cstring>
#include <cstdlib>
#include <netinet/in.h>
#include <functional>

using func_t = std::function<std::string(const std::string &)>;
extern Log lg;

const uint16_t defaultport = 8080;
const std::string defaultip = "0.0.0.0";
const int size = 1024;

enum
{
    SOCKETERR = 1,
    BINDERR,
};

class udpserver
{
    public:
    udpserver(const uint16_t &port = defaultport, const std::string &ip = defaultip) : ip_(ip), port_(port), isrunning_(false) {}
    ~udpserver()
    {
        if (sockfd_ > 0)
        {
            close(sockfd_);
        }
    }

    public:
    void init()
    {
        // 1.创建socket
        sockfd_ = socket(AF_INET, SOCK_DGRAM, 0);
        if (sockfd_ < 0)
        {
            lg(Fatal, "socket create error, sockfd: %d", sockfd_);
            exit(SOCKETERR);
        }
        lg(Info, "socket create success, sockfd: %d", sockfd_);
        // 2.bind
        struct sockaddr_in local;
        bzero(&local, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);
        // local.sin_addr.s_addr = inet_addr(ip_.c_str());
        local.sin_addr.s_addr = INADDR_ANY;

        int n = bind(sockfd_, (sockaddr *)&local, sizeof(local));
        if (n < 0)
        {
            lg(Fatal, "bind error, errno: %d, strerror: %s", errno, strerror(errno));
            exit(BINDERR);
        }
        lg(Info, "bind success, errno: %d, strerror: %s", errno, strerror(errno));
    }
    void run(func_t func)
    {
        isrunning_ = true;
        char buff[size];
        sockaddr_in client;
        socklen_t sz = sizeof(client);
        while (isrunning_)
        {
            ssize_t n = recvfrom(sockfd_, buff, sizeof(buff) - 1, 0, (sockaddr *)&client, &sz);
            if (n < 0)
            {
                lg(Warning, "recvfrom error, errno: %d, strerror: %s", errno, strerror(errno));
                continue;
            }
            buff[n] = 0;
            // 处理数据
            std::string info = buff;
            std::string echo_string = func(info);
            sendto(sockfd_, echo_string.c_str(), echo_string.size(), 0, (sockaddr *)&client, sz);
        }
    }

    private:
    int sockfd_;     // 网络文件描述符
    std::string ip_; // IP地址,1.将字符串风格转换为uint_t类型,2.转换成网络字节序列
    uint16_t port_;  // 端口号转换成网络字节序列
    bool isrunning_;
};--

void Usage(string proc)
{
    cout << "\n\rUsage: " << proc << " port[1024+]" << endl;
}

string handler(const string &str)
{
    cout << str << endl;
    string ret = "server get a message: ";
    ret += str;
    return ret;
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(0);
    }
    uint16_t port = stoi(argv[1]);
    unique_ptr<udpserver> svr(new udpserver(port, "127.0.0.1"));
    svr->init();
    svr->run(handler);
    return 0;
}

客户端

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <cstring>
#include <cstdlib>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "log.hpp"
extern Log lg;

void Usage(std::string proc)
{
    std::cout << "\n\rUsage: " << proc << " serverip serverport\n"
              << std::endl;
}
int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        Usage(argv[0]);
        return 0;
    }
    std::string serverip = argv[1];
    uint16_t serverport = std::stoi(argv[2]);
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        std::cerr << "socket error" << std::endl;
        exit(1);
    }

    sockaddr_in server;
    bzero(&server, 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;
    char buff[1024];
    while (true)
    {
        std::cout << "client say@ ";
        std::getline(std::cin, message);
        sendto(sockfd, message.c_str(), message.size(), 0, (sockaddr *)&server, sizeof(server));
        sockaddr_in temp;
        socklen_t len = sizeof(temp);
        ssize_t n = recvfrom(sockfd, buff, sizeof(buff) - 1, 0, (sockaddr *)&temp, &len);
        if (n > 0)
        {
            buff[n] = 0;
            std::cout << buff << std::endl;
        }
    }

    close(sockfd);
    return 0;
}

5.4服务器实现执行指令

#include <stdio.h>
FILE *popen(const char *command, const char *type);
//是一个封装起来的管道和子进程执行命令的接口,会自动建立管道,让子进程执行命令并将子进程的执行结果通过管道返回给父进程;
//第一个参数是子进程要执行的命令,第二个参数是对打开文件的方式,读写;
//返回值是用来进行获取执行结果的;
int pclose(FILE *stream);
char *fgets(char *s, int size, FILE *stream);
//读取一行,当读到EOF/空时返回nullptr;
bool safecheck(const string &cmd)
{
    int issafe = false;
    vector<string> keyword;
    keyword.push_back("rm");
    keyword.push_back("mv");
    keyword.push_back("kill");
    for (auto &e : keyword)
    {
        auto pos = cmd.find(e);
        if (pos != string::npos)
        {
            return issafe;
        }
    }
    issafe = true;
    return issafe;
}

string execute(const string &cmd)
{
    if (!safecheck(cmd))
    {
        return "unsafe";
    }
    FILE *fp = popen(cmd.c_str(), "r");
    if (fp == nullptr)
    {
        perror("popen error: ");
        return "error";
    }
    char buff[4096];
    string ret;
    while (true)
    {
        char *res = fgets(buff, sizeof(buff), fp);
        if (res == nullptr)
        {
            break;
        }
        ret += buff;
    }
    cout << "get a cmd: " << cmd << endl;
    pclose(fp);
    return ret;
}

​ Xshell的原理就是,远端执行了一个22服务,即ssh,客户端发送指令,服务端进行执行后返回结果;

在这里插入图片描述

5.5Windows和Linux通信

#include<iostream>
#include<WinSock2.h>//网络套接字接口

#pragma comment(lib,"ws2_32.lib")//链接静态库

using namespace std;

int main()
{
	cout << "hello client" << endl;
	WSADATA wsd;//创建变量
	int n = WSAStartup(MAKEWORD(2, 2), &wsd);//初始化
    //通信过程
	WSACleanup();//释放变量
	return 0;
}
#define _WINSOCK_DEPRECATED_NO_WARNINGS 1
#include<iostream>
#include<WinSock2.h>//网络套接字接口
#include<string>

#pragma comment(lib,"ws2_32.lib")//链接静态库

using namespace std;
const uint16_t serverport = 8080;
const string serverip = "60.205.138.126";
int main()
{
    cout << "hello client" << endl;
    WSADATA wsd;
    int n = WSAStartup(MAKEWORD(2, 2), &wsd);
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        cout << "socket error" << endl;
    }
    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;
    char buff[1024];
    while (true)
    {
        std::cout << "client say@ ";
        std::getline(std::cin, message);
        sendto(sockfd, message.c_str(), message.size(), 0, (sockaddr*)&server, sizeof(server));
        sockaddr_in temp;
        int len = sizeof(temp);
        int n = recvfrom(sockfd, buff, sizeof(buff) - 1, 0, (sockaddr*)&temp, &len);
        if (n > 0)
        {
            buff[n] = 0;
            std::cout << buff << std::endl;
        }
    }
    closesocket(sockfd);
    WSACleanup();
    return 0;
}

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

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

相关文章

<深度学习入门学习笔记P1>——《深度学习》

一、深度学习概述 1.深度学习入门概念及介绍 注&#xff1a; &#xff08;1&#xff09;感知机是深度学习网络算法的起源&#xff0c;神经网络是深度学习算法的中心。 &#xff08;2&#xff09;损失函数和梯度下降是用来对模型优化和训练的一种方式。 &#xff08;3&#xff…

AugmentedReality之路-显示隐藏AR坐标原点(3)

本文介绍如何显示/隐藏坐标原点&#xff0c;分析AR坐标原点跟手机的位置关系 1、AR坐标原点在哪里 当我们通过AugmentedReality的StartARSession函数打开AR相机的那一刻&#xff0c;相机所在的位置就是坐标原点。 2、创建指示箭头资产 1.在Content/Arrow目录创建1个Actor类…

NanoMQ的安装与部署

本文使用docker进行安装&#xff0c;因此安装之前需要已经安装了docker 拉取镜像 docker pull emqx/nanomq:latest 相关配置及密码认证 创建目录/usr/local/nanomq/conf以及配置文件nanomq.conf、pwd.conf # # # # MQTT Broker # # mqtt {property_size 32max_packet_siz…

|行业洞察·趋势报告|《2024旅游度假市场简析报告-17页》

报告的主要内容解读&#xff1a; 居民收入提高推动旅游业发展&#xff1a;报告指出&#xff0c;随着人均GDP的提升&#xff0c;居民的消费能力增强&#xff0c;旅游需求从传统的观光游向休闲、度假游转变&#xff0c;国内人均旅游消费持续增加。 政府政策促进旅游市场复苏&…

对象内存布局

对象头 对象标记Mark Word 所以New一个对象 没有其他信息 就是16字节 Object obj = new Object();

设计模式之原型模式讲解

原型模式本身就是一种很简单的模式&#xff0c;在Java当中&#xff0c;由于内置了Cloneable 接口&#xff0c;就使得原型模式在Java中的实现变得非常简单。UML图如下&#xff1a; 我们来举一个生成新员工的例子来帮助大家理解。 import java.util.Date; public class Employee…

Git--08--Git分支合并操作

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 Git分支合并操作案例流程客户端&#xff1a;GitExtensions操作步骤&#xff1a;A操作步骤&#xff1a;B操作步骤&#xff1a;C操作步骤&#xff1a;D操作步骤&#…

Ubuntu20.04安装OpenCV并在vsCode中配置

1. 安装OpenCV 1.1 安装准备&#xff1a; 1.1.1 安装cmake sudo apt-get install cmake 1.1.2 依赖环境 sudo apt-get install build-essential libgtk2.0-dev libavcodec-dev libavformat-dev libjpeg-dev libswscale-dev libtiff5-dev sudo apt-get install libgtk2.0-d…

opencv如何利用掩码将两张图合成一张图

最近在学opencv&#xff0c; 初学者。 里面有提到如何将两张图合成一张图&#xff0c; 提供了两个方法 一种是直接通过图片透明度权重进行融合 img1 cv.imread(ml.png) img2 cv.imread(opencv-logo.png) dst cv.addWeighted(img1,0.7,img2,0.3,0) cv.imshow(dst,dst) cv.…

iOS —— 初识KVO

iOS —— 初始KVO KVO的基础1. KVO概念2. KVO使用步骤注册KVO监听实现KVO监听销毁KVO监听 3. KVO基本用法4. KVO传值禁止KVO的方法 注意事项&#xff1a; KVO的基础 1. KVO概念 KVO是一种开发模式&#xff0c;它的全称是Key-Value Observing (观察者模式) 是苹果Fundation框架…

MySQL ② —— 索引原理

1. 索引 1.1 分类 主键索引、唯一索引、普通索引、组合索引、以及全文索引 主键索引 非空唯一索引&#xff0c;一个表只有一个主键索引&#xff1b;在 innodb 中&#xff0c;主键索引的 B 树包含表数据信息。 唯一索引 不可以出现相同的值&#xff0c;可以有 NULL 值。 …

3.28学习总结

java 封装 封装体现了java的面向对象的特点,用户不用知道程序是如何运行的,只用按照所给的格式输入参数,便可得到对应的结果. 一个完整的封装需要每个实例变量都用private来修饰并拥有相应的public getter和setter方法. 代码 public class girl {private int age;public st…

TABLE使用篇之奇门异术

table使用时候有时候会有下面界面 hover提示框&#xff0c;用element的el-popover可以显示该操作&#xff0c;但是会发现 取消操作的时候&#xff0c;el-popover不会自动消失&#xff0c;虽然失去焦点改框会自动消失&#xff0c;但是看起来对用户不是很友好 解决办法&#xff…

CDH集群hive初始化元数据库失败

oracle数据库操作&#xff1a; 报错如下&#xff1a;命令 (Validate Hive Metastore schema (237)) 已失败 截图如下&#xff1a; 后台日志部分摘录&#xff1a; WARNING: Use “yarn jar” to launch YARN applications. SLF4J: Class path contains multiple SLF4J binding…

Vite 为什么比 Webpack 快?

目录 1. Webpack 的构建原理 2. Script 的模块化&#xff08;主流浏览器对 ES Modules 的支持&#xff09; 3. Webpack vs Vite 开发模式的差异 对 ES Modules 的支持 底层语言的差异 热更新的处理 1. Webpack 的构建原理 前端之所以需要类似于 Webpack 这样的构建工具&…

vue纯前端过滤嵌套数据,通过关键字搜索过滤嵌套数据

1.过滤效果&#xff1a; 2. cardList 数据源&#xff1a; [ { "id": 4, "createTime": "2024-03-28 02:47:18", "updateTime": "2024-03-28 02:47:18", "uniqueId": "…

前端学习-CSS基础-Day3

一、CSS三大特性 1.1层叠性 相同选择器给设置相同的样式&#xff0c;此时一个样式就会覆盖&#xff08;层叠&#xff09;另一个冲突的样式。层叠性主要解决样式冲突的问题 层叠性原则&#xff1a; 1.样式冲突&#xff0c;遵循的原则是就近原则&#xff0c;哪个样式离结构近&a…

React系列之合成事件与事件处理机制

文章目录 React事件处理机制原生事件的事件机制事件代理&#xff08;事件委托&#xff09; 合成事件使用合成事件目的合成事件原生事件区别事件池 原生事件和React事件的执行顺序e.stopPropagation() React17事件机制的修改 React事件处理机制 react 事件机制基本理解&#xf…

Maven配置国内镜像-阿里云仓库镜像

使用自己安装maven环境时&#xff1a; 打开解压目录下conf/settings.xml文件 使用Idea自带的Maven时&#xff1a; 打开Idea安装路径\plugins\maven\lib\maven3\conf\settings.xml文件 在mirrors节点中加入如下配置&#xff1a; <!-- 加入如下mirror节点 使用国内阿里云仓…

fastadmin学习05-开启debug以及配置

FastAdmin 框架提供了对 .env 环境变量配置的支持&#xff0c;并附带一个默认示例文件 .env.sample。在安装后&#xff0c;框架并不会自动启用 env 环境变量&#xff0c;需要手动将 .env.sample 复制为 .env 并进行配置。 如果不开启.env会读取database.php中的配置 下面测试…