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

五、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.mfbz.cn/a/497068.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【常见面试题】JS 发布者、订阅者模式

面试中经常出现问到如何实现JS 发布者、订阅者模式。下面是ES5实现发布订阅模式。 1、直接上代码。 function EventEmitter() {this.events {}; }; // 订阅者 EventEmitter.prototype.on function(ename, callback) {if (!this.events[ename]) {// 初始化创建订阅&#xff…

C++ 控制语句(二)

一 break continue和goto语句 1 break语句 在switch语句中&#xff0c;分隔case子句&#xff0c;跳出switch语句。 在循环语句中可以立即终止循环语句的执行。 2 continue语句 功能:在一次循环过程中,跳过continue语句以下的语句,直 接进入下一次循环操作。 3 goto语句 …

软考98-上午题-【信息安全】-防火墙

一、考试概述 该内容与计算机网络关联。 分值&#xff1a;2分 二、防火墙 防火墙 (Firewall) 是建立在内外网络边界上的过滤封锁机制&#xff0c;它认为内部网络是安全和可信赖的&#xff0c;而外部网络是不安全和不可信赖的。 防火墙的作用是防止不希望的、未经授权地进出…

CCF-CSP认证考试 202303-5 施肥 35/60/75/100分题解

更多 CSP 认证考试题目题解可以前往&#xff1a;CSP-CCF 认证考试真题题解 原题链接&#xff1a; 202303-5 施肥 时间限制&#xff1a; 2.0s 内存限制&#xff1a; 1.0GB 问题描述 春天到了&#xff0c;西西艾弗岛上的 n n n 块田地需要施肥了。 n n n 块田地编号为 1 , 2…

Qt消息机制和事件

Qt消息机制和事件 Qt消息机制和事件--2 事件 事件&#xff08;event&#xff09;是由系统或者 Qt 本身在不同的时刻发出的。当用户按下鼠标、敲下键盘&#xff0c;或者是窗口需要重新绘制的时候&#xff0c;都会发出一个相应的事件。一些事件在对用户操作做出响应时发出&…

【数据结构】顺序表的实现——静态分配

&#x1f388;个人主页&#xff1a;豌豆射手^ &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;数据结构 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进…

matplotlib画图:子图中坐标轴与标题重合...

如下图 只要在代码最后加入 plt.tight_layout() 就可以自动调节

江苏开放大学2024年春《市政管理学050011》第一次形考作业参考答案

答案&#xff1a;更多答案&#xff0c;请关注【电大搜题】微信公众号 答案&#xff1a;更多答案&#xff0c;请关注【电大搜题】微信公众号 答案&#xff1a;更多答案&#xff0c;请关注【电大搜题】微信公众号 电大搜题 多的用不完的题库&#xff0c;支持文字、图片搜题…

C语言编译和链接理解

一. 翻译环境和运行环境 二. 翻译环境&#xff1a;预编译编译汇编链接 三运行环境 一. 翻译环境和运行环境 &#xff1a; 1.翻译环境和运行环境&#xff1a;在ANSI C的任何⼀种实现中&#xff0c;存在两个不同的环境。第1种是翻译环境&#xff0c;在这个环境中源代码被转换为…

散热风扇220v交流12v直流12038轴流风机配电箱机柜散热风扇15050

品牌&#xff1a;威驰 颜色分类&#xff1a;11025风扇220v含油,11025风扇220v纯铜双滚珠,12025风扇220v含油,12025风扇220v纯铜双滚珠,12025风扇24V纯铜双滚珠,12025风扇12V纯铜双滚珠,12038风扇220v含油,12038风扇110V含油,12038风扇220v纯铜双滚珠,12038风扇110v纯铜双滚珠,…

如何把PNG图片转换成CAD图纸DWG格式

环境&#xff1a; CAD2021 PNG图片 问题描述&#xff1a; 如何把PNG图片转换成CAD图纸DWG格式 解决方案&#xff1a; 将PNG图像转换为CAD文件&#xff08;如DXF或DWG格式&#xff09;是设计和工程领域中常见的需求之一。幸运的是&#xff0c;有几种工具和软件可以帮助完成…

幻兽帕鲁服务器多少钱?2024年Palworld服务器价格整理

2024年全网最全的幻兽帕鲁服务器租用价格表&#xff0c;阿里云幻兽帕鲁游戏服务器26元1个月、腾讯云32元一个月、京东云26元一个月、华为云24元1个月&#xff0c;阿腾云atengyun.com整理最新幻兽帕鲁专用4核16G、8核16G、8核32G游戏服务器租用价格表大全&#xff1a; 阿里云幻…

Java异常机制

异常体系图 Throwable Throwable 是 Java 语言中所有错误与异常的超类。 Throwable 包含两个子类&#xff1a;Error&#xff08;错误&#xff09;和 Exception&#xff08;异常&#xff09;&#xff0c;它们通常用于指示发生了异常情况。 Throwable 包含了其线程创建时线程执…

计算机组成原理 浮点数溢出

阶码同样有位数限制 浮点数的溢出并不以尾数溢出来判断&#xff0c;尾数溢出可以通过右规操作得到纠正。运算结果是否溢出主要看结果的指数是否发生了上溢&#xff0c;因此是由指数上溢来判断的。可能导致溢出的情况&#xff1a;即所有涉及阶码运算的情况 右规和尾数舍入&…

HBase Shell基本操作

一、进入Hbase Shell客户端 先在Linux Shell命令行终端执行start-dfs.sh脚本启动HDFS&#xff0c;再执行start-hbase.sh脚本启动HBase。如果Linux系统已配置HBase环境变量&#xff0c;可直接在任意目录下执行hbase shell脚本命令&#xff0c;就可进入HBase Shell的命令行终端环…

【JavaWeb】Day22.maven安装介绍

目录 一.初识Maven 什么是maven? Maven的作用 二.Maven概述 1. Maven介绍 2.Maven模型 3. Maven仓库 三. Maven安装 1.下载 2. 安装步骤 1. 解压安装 2. 配置本地仓库 3.配置阿里云私服 4. 配置Maven环境变量 一.初识Maven 什么是maven? Maven是apache旗下的一个…

2024年数字IC秋招-复旦微电子-数字前端/验证-笔试题

文章目录 前言一、基础题/选做题1、什么是DMA&#xff0c;主要优点是什么&#xff0c;为什么这是它的优点2、SV的代码如下&#xff0c;给出$display中变量的值3、列出4bit格雷码编码&#xff0c;画出二进制码转格雷码电路图4、如何从慢时钟域捕获快时钟域脉冲信号&#xff0c;画…

行为管理设置能监控或者检测哪些东西

3 月 27 日&#xff0c;国新办举行“推动高质量发展”系列主题新闻发布会&#xff0c;浙江省省长王浩&#xff1a;全省市场经营主体 1040 万户&#xff0c;相当于平均每 6.5 个浙江人就有 1 个老板。 不由让小编想到&#xff0c;这么多老板&#xff0c;那么老板创办企业也怪不容…

蓝桥杯省三保底代码——数显+按键功能实现

目录 前言 一、为什么能保底省三 二、数显模块的实现 1.数码管显示​编辑 1&#xff09;断码表 2&#xff09;位选 3&#xff09;段选 4&#xff09;扫描 2.菜单 三、按键功能的实现 1.按键扫描 2.菜单切换 四、完整代码演示 五、结语 前言 上一期介绍全家桶时&…

【容器源码篇】Set容器(HashSet,LinkedHashSet,TreeSet的特点)

文章目录 ⭐容器继承关系&#x1f339;Set容器&#x1f5d2;️HashSet源码解析构造方法public HashSet()public HashSet(Collection<? extends E> c)public HashSet(int initialCapacity, float loadFactor)HashSet(int initialCapacity, float loadFactor, boolean dum…
最新文章