UDP网络套接字编程

这篇具有很好参考价值的文章主要介绍了UDP网络套接字编程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

先来说说数据在网络上的传输过程吧,我们知道系统其实终究是根据冯诺依曼来构成的,而网络数据是怎么发的呢?

其实很简单,网络有五层。如下:

UDP网络套接字编程,Linux相关知识,网络,udp,网络协议

如上图,我们知道的是,每层对应的操作系统中的那些地方,有些可能说是网络有七层,其实和这个五层一样的。下面我们说说数据是怎么运输的在网络中,如下图:

UDP网络套接字编程,Linux相关知识,网络,udp,网络协议如上图,其实数据在网络中是自顶向下,然后在通过以太网的网线传输到另一个主机上,在自底向上,就可以收到了,前提是在同一个局域网中,如果不在一个局域网,肯定会经过路由器的,这里就不详细说了,主要说说我们的udp协议。

我们知道了网络的五层,那么每层其实都与对应的协议等。udp协议对应在传输层(运输层)。那么我们来看看如何用udp协议实现套接字编程吧。先来看看代码:

#include <iostream>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <unordered_set>
#include <unordered_map>
using namespace std;
#define NUM 1024
int main(int argc, char *argv[])
{
    unordered_map<uint16_t,sockaddr_in> usdate;
    // 创建套接字
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0)
    {
        cout << "sock enrro" << endl;
        exit(1);
    }
    // 绑定
    sockaddr_in se;
    memset(&se, 0, sizeof(se));
    se.sin_family = AF_INET;
    se.sin_port = htons(atoi(argv[2]));
    se.sin_addr.s_addr = inet_addr(argv[1]);
    int ret = bind(sock, (sockaddr *)&se, sizeof(se));
    if (ret < 0)
    {
        cout << "bind enrro" << endl;
        exit(2);
    }
    // 服务端    1.0版本
    // 可以开始读取
    // sockaddr_in reader;
    // socklen_t size = sizeof(reader);
    // char buffer[NUM];
    // while (true)
    // {
    //     ssize_t r = recvfrom(sock, buffer, sizeof(buffer) - 1, 0, (sockaddr *)&reader, &size);
    //     buffer[r] = '\0';
    //     if (r > 0)
    //     {
    //         cout << buffer << endl;
    //     }
    //     else
    //         break;
    //     sendto(sock, buffer, sizeof(buffer), 0, (sockaddr *)&reader, size);
    //     memset(buffer, 0, sizeof(buffer));
    // }
    // close(sock);
    // 服务器 2.0版本 实现群聊
    char buffer[NUM];
    memset(buffer, 0, NUM);
    sockaddr_in reader;
    socklen_t size = sizeof(reader);
    while (true)
    {
        ssize_t s = recvfrom(sock, buffer, sizeof(buffer) - 1, 0, (sockaddr *)&reader, &size);
        usdate.insert(make_pair(reader.sin_port, reader));
        cout << "插入成功" << endl;
        cout << ntohs(reader.sin_port) <<" "<< inet_ntoa(reader.sin_addr)<< '#' << " "
             << ":" << buffer << endl;
        if (s > 0)
        {
            for (const auto &e : usdate)
                sendto(sock, buffer, sizeof(buffer), 0, (sockaddr *)&(e.second), sizeof(e.second));
            memset(buffer, 0, NUM);
        }
        else
            break;
    }
    close(sock);
    return 0;
}
#include <iostream>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
using namespace std;
#define NUM 1024
void *reads(void *args)
{
    // 线程分离
    pthread_detach(pthread_self());
    char buffer[NUM];
    // 清空buffer
    memset(buffer, 0, NUM);
    int *sc = static_cast<int *>(args);
    sockaddr_in reader;
    socklen_t len = sizeof(reader);
    while (true)
    {
        ssize_t s = recvfrom(*sc, buffer, sizeof(buffer) - 1, 0, (sockaddr *)&reader, &len);
        if (s > 0)
        {
            cout << buffer << endl;
            memset(buffer, 0, NUM);
        }
        else
            break;
    }
    return nullptr;
}
int main(int argc, char *argv[])
{
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0)
    {
        cout << "sock enrro" << endl;
        exit(1);
    }

    char buffer[NUM];
    memset(buffer, 0, NUM);
    pthread_t tid;
    pthread_create(&tid, nullptr, reads, &sock);

    sockaddr_in clinet;
    memset(&clinet, 0, sizeof(clinet));
    clinet.sin_family = AF_INET;
    clinet.sin_addr.s_addr = inet_addr(argv[1]);
    clinet.sin_port = htons(atoi(argv[2]));
    while (true)
    {
        cout << "你要输入" << endl;
        cin >> buffer;
        ssize_t s = sendto(sock, buffer, sizeof(buffer), 0, (sockaddr *)&(clinet), sizeof(clinet));
        if (s > 0)
            memset(buffer, 0, NUM);
        else
            break;
    }
    close(sock);
    return 0;
}

这是我的服务端和客户端的代码,分了单人聊天和多人聊天。下面就讲解一下吧。

什么是端口号:主机中能表示一个唯一的进程的编号

什么是ip地址:其实ip地址是网络层对应的主机地址。

什么是mac地址:这个网卡的地址,一般出厂的时候就会确定,且不能修改

什么是套接字:IP+端口号

我们首先可以根据套接字找到网络中唯一的一个主机上进程,此处不考虑ip地址重复问题。假设ip地址不重复。所以我们要进行udp套接字编程,首先要创建套接字。也就是我上图代码中的socket这个函数,然后绑定地址和端口,这个就可以用我们main函数中的参数了。创建完套接字和绑定完成以后,我们就可以通信了,我们用的这些函数其实就是系统调用,是udp的一些函数暴露给用户层的系统调用。

大概知道了怎么用udp编程,那么此时有些伙伴可能有些疑问了。我们在系统层面上pid也可以表示进程的唯一性,为啥不用PID表示端口号呢?其实也很简单,原因就是网络层是这么表示的,就好比你的名字一样,在外面大家都叫你名字,回到家家里面的人都叫你小名,一样的道理。

然后就是有些人可能没有理解数据是怎么从下往上,从上往下的。其实很好理解,因我们在写代码的时候,我们是属于用户层的。而我们传输层的系统调用接口,那么说明他这个数据肯定是要进内核的,而我们的另一个主机接收到信息后,我们用的打印函数,又是用户层的,所以就类似于一个轮回。所以这样就可以很好的理解了。

然后就是一些编码的注意事项了,在客户端我用了多线程来实现了读数据和写数据的解耦,这个其实在单人聊天中没什么影响,再多人聊天中就不可以了。假设单人聊天就要先发在读。因为再多人聊天中,我们预期是一个人发,多个人收,如果还是用这个代码的话,那么 如果开启服务端的时候,多个人你同时建立连接,那么此时如果有其中一个人发了信息,并且假设其他人都没有发信息,那么此时就会导致其他人卡在写的界面,因为他们没有写,所以没办法读信息。所以此时我们这里必须要实现成多线程,一个写,一个读,读写解耦。两个互不影响。建议使用线程,不用进程,且不说多进程可不可以实现这个功能,就算是实现了,那么此时它的消耗是很大的。(多进程也可以实现这个功能),如果用多进程,那么此时我们要考虑的是,如何回收这个子进程,肯定不可以阻塞等待,如果用waitpid且不是阻塞等待的话,那么此时我们要写成循环,要不断去检测子进程是否完成任务。或是可以在子进程中在frok,让孙子进程执行任务,子进程退出,此时就会形成孤儿进程,会被1号进程领养,所以不用担心资源泄露,但是这样很明显很麻烦,还不如用线程,且消耗还比进程小。

以上就是这篇文章的内容,希望大家支持,如果对你有用,希望支持一下!!!!文章来源地址https://www.toymoban.com/news/detail-758711.html

到了这里,关于UDP网络套接字编程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【探索Linux】P.28(网络编程套接字 —— 简单的UDP网络程序模拟实现)

    在前一篇文章中,我们详细介绍了UDP协议和TCP协议的特点以及它们之间的异同点。 本文将延续上文内容,重点讨论简单的UDP网络程序模拟实现 。通过本文的学习,读者将能够深入了解UDP协议的实际应用,并掌握如何编写简单的UDP网络程序。让我们一起深入探讨UDP网络程序的

    2024年04月08日
    浏览(78)
  • 网络编程套接字 | UDP套接字

    前面的文章中我们叙述了网络编程套接字的一些预备知识点,从本文开始我们就将开始UDP套接字的编写。本文中的服务端与客户端都是在阿里云的云服务器进行编写与测试的。 在v1的版本中我们先来使用一下前面讲过得一些接口,简单的构建一个udp服务器: 然后运行上述的程

    2024年02月09日
    浏览(38)
  • UDP网络套接字编程

    先来说说数据在网络上的传输过程吧,我们知道系统其实终究是根据冯诺依曼来构成的,而网络数据是怎么发的呢? 其实很简单,网络有五层。如下: 如上图,我们知道的是,每层对应的操作系统中的那些地方,有些可能说是网络有七层,其实和这个五层一样的。下面我们

    2024年02月04日
    浏览(30)
  • 【JaveEE】网络编程之TCP套接字、UDP套接字

    目录 1.网络编程的基本概念 1.1为什么需要网络编程  1.2服务端与用户端 1.3网络编程五元组  1.4套接字的概念 2.UDP套接字编程 2.1UDP套接字的特点  2.2UDP套接字API 2.2.1DatagramSocket类 2.2.2DatagramPacket类  2.2.3基于UDP的回显程序 2.2.4基于UDP的单词查询  3.TCP套接字编程 3.1TCP套接字的特

    2023年04月13日
    浏览(46)
  • 【JavaEE】网络编程之TCP套接字、UDP套接字

    目录 1.网络编程的基本概念 1.1为什么需要网络编程  1.2服务端与用户端 1.3网络编程五元组  1.4套接字的概念 2.UDP套接字编程 2.1UDP套接字的特点  2.2UDP套接字API 2.2.1DatagramSocket类 2.2.2DatagramPacket类  2.2.3基于UDP的回显程序 2.2.4基于UDP的单词查询  3.TCP套接字编程 3.1TCP套接字的特

    2023年04月20日
    浏览(47)
  • 【探索Linux】P.25(网络编程套接字基本概念 —— 预备知识)

    在上一篇文章中,我们深入探讨了Linux网络的基础知识和它的发展历史,为读者揭开了Linux网络技术演变的序幕。我们了解到,Linux网络技术的发展不仅促进了操作系统本身的成熟,还对整个互联网的进步产生了深远的影响。随着网络技术的不断进步,Linux系统在网络通信方面

    2024年04月27日
    浏览(24)
  • 网络编程套接字(3)——Java数据报套接字(UDP协议)

    目录 一、Java数据报套接字通信模型 二、UDP数据报套接字编程 1、DatagramSocket         (1)DatagramSocket构造方法         (2)DatagramSocket方法 2、DatagramPacket         (1)DatagramPacket构造方法         (2)DatagramPacket方法 3、InetSocketAddress 三、代码示例:回显服务

    2024年03月12日
    浏览(41)
  • JavaEE——网络编程(UDP套接字编程)

    概念: Socket 套接字就是操作系统给应用程序提供的网络编程 API。 我们可以认为 socket api 是和 传输层 密切相关的。 我们知道,在传输层中,提供了两个最核心的协议,UDP TCP。 因此,socket api 中也提供了两种风格。UDP TCP。 在这里我们简单认识一下 UDP 和 TCP : UDP : 无连接

    2024年02月13日
    浏览(32)
  • Linux网络编程:线程池并发服务器 _UDP客户端和服务器_本地和网络套接字

    文章目录: 一:线程池模块分析 threadpool.c 二:UDP通信 1.TCP通信和UDP通信各自的优缺点 2.UDP实现的C/S模型 server.c client.c 三:套接字  1.本地套接字 2.本地套 和 网络套对比 server.c client.c threadpool.c   server.c client.c server.c client.c

    2024年02月11日
    浏览(43)
  • 网络编程套接字应用分享【Linux &C/C++ 】【UDP应用 | TCP应用 | TCP&线程池小项目】

    目录 前提知识 1. 理解源ip,目的ip和Macip 2. 端口号 3. 初识TCP,UDP协议 4. 网络字节序 5. socket 编程 sockaddr类型  一,基于udp协议编程  1. socket——创建套接字 2. bind——将套接字强绑定  3. recvfrom——接受数据 4. sendto——发出信息  遇到的问题 (1. 云服务器中以及无法分配I

    2024年04月08日
    浏览(70)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包