Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >初识网络 · udp的基本使用

初识网络 · udp的基本使用

作者头像
_lazy
发布于 2025-04-08 00:38:48
发布于 2025-04-08 00:38:48
8000
代码可运行
举报
文章被收录于专栏:Initial programmingInitial programming
运行总次数:0
代码可运行

前言:

在本文的这个系列,会涉及到不同协议的基本使用到背后的原理机制,那么从一开始我们先实操,比如我们先尝试编写一款具有回显功能的Udp服务器,再尝试对它加一点业务,最后,我们甚至可以使用多线程部分进行服务器的一个升级。

用到多线程的部分比如我们要写一个群聊服务器,像微信的群聊那样,每个人都可以收发消息,当然了,这是后话了,这个的基础建立在了多线程的基础之上,所以我们着重点还是在udp协议本身的使用。

那么本文将会尝试编写两款udp服务器,一个是具有回显功能的udp服务器,一个是带一点点业务的udp服务器,比如带翻译功能的那种。

udp_server_v1

正式开始之前,我们如果不知道从哪里开始,那么我们不妨想想C++是一款具有什么特点的语言,它是一门面向对象的语言吧?

那么在udp_server_v1的这个服务器里面,涉及到的对象有谁?

那肯定是:udp服务器本身

所以首当其冲的就是我们直接先来一个udpserver.hpp再说,即我们要封装一个udp服务器的类:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class udp
{
};

对于一个服务器来说,当我们通过一个服务器转发消息的时候,这个服务器发生了拷贝会怎么样?是不是会存在消息重复,进而会导致内存的问题等?所以对于一个服务器来说,最重要的一个点就是不能进行拷贝。

那么让这个类不能进行拷贝有很多种做法,一种是我们可以私有它的拷贝,私有它的operator==,另一种是我们可以通过让它继承不能发生拷贝的类,比如nocopy这个类,这个类的拷贝和赋值都被私有了。

那么第一个问题:如果禁止拷贝? 就完美的解决了。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pragma once

class nocopy
{
public:
    nocopy(){}
    ~nocopy(){}
    nocopy(const nocopy&) = delete;
    const nocopy& operator=(const nocopy&) = delete;
};

接下来第二个问题是,咱们的udp服务器应该要有哪些成员变量?或者说咱们udp这个对象应该具备哪些属性

首先,对于网络通信来说,就是通过创建了socket套接字,通过socket接口返回了对应的文件fd,我们才得以通信,那么对于服务器来说,知道对应的fd是必不可少的,这是第一个属性了,通信的时候知道了对应的fd,有了fd之后,我们不妨想想什么是真正的socket?

在网络的基础概念中我们提及了网络通信实际上是两个进程在通信,那么我们确认两个进程的唯一标准就是对应的端口号加对应的主机Ip地址。

所以咱们的服务器应该要有的属性还要有port 和 std::string ip,可是事实真的如此吗

实际上咱们的服务器并不需要特定的Ip地址,咱们的服务器填充对应的sockaddr_in的信息的时候,如果我们指定了特定的ip地址,那么也就代表咱们这个服务器它只能接收特定地址的数据,但是如果咱们的本机具有多个ip呢?

那么数据的目的地址不管是A还是B还是C,咱们是不是都可以接收了?所以一般对于服务器的信息填充,咱们一般设置为0,到后面使用的就是对应的宏了。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static const int gsockfd = -1;
static const uint16_t gport = 8888;

class udpserver
{

public:
    udpserver(int sockfd = gsockfd,uint16_t port = gport)
        : _isrunning(false),_sockfd(sockfd), _port(port)
    {
    }

    ~udpserver()
    {
        if(_sockfd < 0) ::close(_sockfd);
    }

private:
    uint16_t _port;
    int _sockfd;
    /* std::string _serverip;  server端不需要ip */
    bool _isrunning;
};

到了这里,咱们对于udpserver的大体框架咱们就清楚了。

那么对于一个服务器来说,一般涉及到的就是初始化服务器和启动对应的服务,比如咱们这里的服务就是回显对应的字符串。

那么我们先考虑第一个问题,我们应该如何初始化咱们的服务器

对于初始化服务器来说,咱们可以简单的分为这么几步,首先我们要创建对应的套接字,接着是填充对应的服务器信息,最后是bind套接字和对应的服务器信息,对于udp来说,它本身是比较简单的,所以初始化服务器来说,也是比较简单的。

首先,创建对应的套接字我们使用的是socket:

它涉及到的头文件是sys/types.h sys/socket.h,其中有三个参数,分为是domain type protocol,对于第一个参数来说,它表示我们选择什么协议,我们这里选择IPv4的协议,对应的就是AF_INET。对于第二个参数来说,我们因为使用的是UDP协议,所以我们往下看我们会看到这么一句话:

翻译过来就是无连接的,不可靠传输。这实际上对应上了udp的特点。所以第二个类型参数我们选择这个。第三个参数我们直接传0就行,咱们暂时不管。

到这里咱们的套接字创建就好了,因为实际上返回的是文件描述符,而在底层实现中,文件描述符是没有负数的,所以一旦创建失败,它就会返回-1,我们可以通过返回值来判断是否创建成功了。

接着就是服务器信息的查询,这里我们唯一要注意一个点就是主机转网络以及对于服务器本身结构体信息的先清空再填充。清空的时候如果我们清空错了是有可能导致后面的sin_family出错的等。

这里我们简单认识一下scokaddr_in结构体吧,它就是我们要认识的结构体:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/* Structure describing an Internet socket address.  */
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)];
  };

这是它的源文件定义,我们看in_port_t sin_port,这实际上就是对应的端口号,我们再转到in_port_t的定义也没啥用,实际上就是一个16位的整数,sin_addr就比较神奇了,它实际上是一个ip地址,但是这个Ip地址再次被封装了起来,使用的是in_addr:

当我们进到in_addr的里面,会发现这个结构体只有一个内容,就是32位整数的数据,也就是4字节的数据这是。

有了对应的ip和Port,我们还有一个对应的地址簇,当我们转到它的定义里面去的时候,会发现里面这是一个简单的宏定义,其中使用到了我们在C语言阶段学习的连接符##,这里其实就是简单定义了一个sa_family_t类型的sin_family参数,我们不管那么多,用的时候我们直接填充就可以了。

以上是填充的基本认识。

填充完毕,也就是我们具备了对应的socket套接字和服务器对应的结构体,光有那可不行,我们需要把这两个bind起来,就像我们有锤子和钉子,不一起使用怎么能订住东西呢?

对于bind函数的使用是:

可以看到bind对应的参数我们都有了,直接使用之后,判断对应的返回值就可以了,那么到了这里,我们的初始化服务器就完成了:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 void Initserver()
    {
        // create sockfd
        _sockfd = socket(AF_INET, SOCK_DGRAM, 0); // 别又int
        if (_sockfd < 0)
        {
            std::cout << "sockfd error" << std::endl;
            exit(SOCKFD_ERROR);
        }
        std::cout << "sockfd success: " << _sockfd << std::endl;

        // server imformation
        struct sockaddr_in server;
        memset(&server, 0, sizeof(server));
        server.sin_family = AF_INET;
        server.sin_port = htons(_port); // htons
        server.sin_addr.s_addr = INADDR_ANY;

        // bind
        socklen_t len = sizeof(server);
        int n = ::bind(_sockfd, (struct sockaddr *)&server, len);
        if (n < 0)
        {
            std::cout << "Bind error" << std::endl;
            exit(BIND_ERROR);
        }
        std::cout << "Bind success" << std::endl;
    }

这里面的宏参数都是笔者自己定义的,这样看起来更系统化一点。

接下来我们要考虑的问题就是服务器初始化结束之后,我们应该如何启动对应的服务

到这里可能有同学就说了,服务嘛,咱们定义一个函数,客户端访问的时候我们就在服务器这里调用这个函数就可以了。

实际上这样是可以的,只不过这种办法丧失了解耦这个近乎完美的功能

为什么这么说呢?因为在初识协议的部分,协议的一个非常大的作用是可以实现分层的解耦问题,比如人与人通信,协议出错了我们可以到对应的层发现并解决问题,如果我们把所有的都糅合在了一起,那不就太乱了吗?

所以我们开发的时候要遵从的一个非常重要的点是高耦合低内聚

那么在服务器这里,我们要实现的就是,服务器能执行方法,但是这个方法是什么它不知道,它只知道调用就可以了。

不过在回显服务器这里,我们暂时不用考虑这么多,这里叭叭叭这么多是实际上是为了给udp_server_v2打基础。

在这里我们启动的服务就是返回收到的字符串,那么势必要用到两个函数:

一个是recvfrom一个是sendto函数,光从名字咱们也能知道这两个函数是干什么用的。

对于recvfrom函数来说,对应的参数分别是套接字,接收缓冲区,接收字节大小,标志位,接收的机器的结构体和对应的大小。

你别看这么多,简单想清楚了写的十分顺溜,我们从客户端那里接收到了消息,消息存放到哪里?从哪个套接字接收?缓冲区是哪个?缓冲区的大小是多大?

这些问题咱们想清楚了,参数那就太简单了。

对于sendto同理。咱这里就不解释了。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    void start()
    {
        _isrunning = true;
        while (_isrunning)
        {
            // recvfrom
            char inbuffer[1024];
            struct sockaddr_in clinet;
            socklen_t len = sizeof(clinet);
            ssize_t n = recvfrom(_sockfd, inbuffer, sizeof(inbuffer) - 1, 0, (struct sockaddr *)&clinet, &len);
            if (n < 0)
            {
                perror("recvfrom");
                exit(RECVFORM_ERROR);
            }
            // send
            else
            {
                std::string info = "[lazy_client say]#";
                info += inbuffer;
                std::cout << info << std::endl;

                std::string ans;
                ans += inbuffer;
                ssize_t n = sendto(_sockfd, ans.c_str(), ans.size(), 0, (struct sockaddr*)&clinet, len);
                if(n < 0)
                {
                    std::cout << "sendto error" << std::endl;
                    exit(SENDTO_ERROR);
                }
            }
        }
        _isrunning = false;
    }

那么在消息回显的这个功能这里,咱们只需要做两件事,先收消息,然后发消息就可以了。

对于udpserver.hpp咱们也就基本完成了

接下来就是客户端的编写和服务端的编写

对于服务端来说:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include "udpserver.hpp"
#include <memory>


int main(int args, char* argv[])
{
    if(args != 2)
    {
        std::cout << "parameter num error!!!" << std::endl;
        exit(SERVER_PARAMETER_ERROR);
    }
    
    int _serverport = std::stoi(argv[1]);

    std::unique_ptr<udpserver> usvr = std::make_unique<udpserver>(_serverport); // C++14
    usvr->Initserver();
    usvr->start();

    return 0;
}

老实说,没有什么特别要注意的,不过是我们可以通过智能指针new一个udpserver的实例化出来,然后初始化,启动服务就行。

不过,有意思的是服务器虽然说不需要IP地址,但是它需要自己的端口号,咱们可以自己指定,但是指定的端口号不能特殊了,像什么80端口号,就不是我们能用的了。

而端口号的传入,我们可以使用命令行参数进行参数,同理,客户端是需要的,所以我们在客户端也是都可以这么干的。

对于客户端来说:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

先短暂的打个插曲,这几个头文件,在网络中基本是刚需,所以我们可以简单的记忆一下。

好了,步入整题,对于客户端来说,也就是发个消息而已,不过和服务器一样,它们都有一个共同的点是服务一旦启动了,如果不主动退出就一直运行,所以我们一般来说都是使用while(true)来循环走这个过程。

这里有一个问题,对于服务器来说,服务器需要bind自己的socket和sockaddr_in的信息,换句话说,服务器需要bind套接字和端口号ip那些的关系,客户端是否需要bind呢

答案是肯定的,但是,客户端并不需要显示的bind对应的端口号ip,因为这些都让操作系统给它做了,所以对于客户端要考虑的事儿就是怎么收发消息,那就简单了,用前面的函数就可以了:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int main(int args, char* argv[])
{
    if(args != 3)
    {
        std::cout << "client parameter error!!!" << std::endl;
        exit(-1);
    }

    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sockfd < 0) exit(-2);

    while(true)
    {
        // sendto
        struct sockaddr_in server;
        memset(&server,0, sizeof(server));
        server.sin_family = AF_INET;
        server.sin_addr.s_addr = inet_addr(argv[1]);
        server.sin_port = htons(std::stoi(argv[2]));

        std::string information;
        std::getline(std::cin, information);
        ssize_t n = ::sendto(sockfd, information.c_str(), sizeof(n), 0, (struct sockaddr*)&server, sizeof(server));
        if(n < 0)
        {
            perror("sendto");
            exit(-3);
        }
        // recvfrom
        char inbuffer[1024];
        struct sockaddr_in temp;
        socklen_t len = sizeof(temp);
        ssize_t m = ::recvfrom(sockfd, inbuffer, sizeof(inbuffer) - 1, 0, (struct sockaddr*)&temp, &len);
        inbuffer[m] = 0;
        if(m < 0)
        {
            perror("recvfrom");
            exit(-4);
        }
        std::cout << "[lazy_server say]#" << inbuffer;
    }
    return 0;
}

虽然这里比较草率,详细的主要还是在服务器介绍的比较多,这里其实类比一下就可以了。


udp_server_v2

对于v2版本,咱这里就把相关的文件传上来,因为这个版本要注意的也就只有解耦和一点std::bind的使用,所以笔者这里选择上传对应的代码了:

Common.h:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pragma once

enum
{
    SOCKFD_ERROR = 1,
    BIND_ERROR,
    RECVFORM_ERROR,
    SENDTO_ERROR,
    SERVER_PARAMETER_ERROR,
    CLIENT_PARA_ERRROR,
    FSTREAM_ERROR
};

dict.hpp

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pragma once

#include <unordered_map>
#include <iostream>
#include <fstream>
#include "Common.hpp"

static const std::string sep = ":";

class Dict
{
private:
    void Dict_init()
    {
        // open profiles 
        std::fstream in(_path);
        if(!in.is_open())
        {
            perror("is_open");
            exit(FSTREAM_ERROR);
        }

        // open success
        std::string info;
        while(std::getline(in, info))
        {
            // 定位
            size_t pos = info.find(sep);
            if(pos == std::string::npos) continue; // empty line
            
            // 分割
            std::string key = info.substr(0, pos);
            if(key.empty()) continue; // not complete
            std::string value = info.substr(pos+sep.size());
            if(value.empty()) continue; // not complete

            // 插入
            _dict.insert(std::make_pair(key,value));

        }
        in.close();
    }

public:
    Dict(std::string path = "./dict.txt")
        :_path(path)
    {
        Dict_init();
    }

    std::string Translate(const std::string& word)
    {
        auto iter = _dict.find(word);
        if(iter == _dict.end()) return "Not exist";
        return iter->second;
    }

private:
    std::unordered_map<std::string, std::string> _dict;
    std::string _path;

};

dict.txt

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
apple:苹果
banana:香蕉
cat:dog:book:pen:happy:快乐的
sad:悲伤的
run:jump:teacher:老师
student:学生
car:汽车
bus:公交车
love:hate:hello:你好
goodbye:再见
summer:夏天
winter:冬天

InetAddr.hpp

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pragma once

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


class InetAddr
{
private:
    void ToHost(struct sockaddr_in addr)
    {
        _port = htons(addr.sin_port);    
        _ip = inet_ntoa(addr.sin_addr);
    }

public:
    InetAddr(struct sockaddr_in addr)
        :_addr(addr)
    {
        ToHost(_addr);
    }

    uint16_t Port()
    {
        return _port;
    }

    std::string IP()  
    {
        return _ip;
    }

private:
    struct sockaddr_in _addr;
    uint16_t _port;
    std::string _ip;
};

clientMain.cc

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <iostream>
#include <unistd.h>
#include <cstring>
#include "Common.hpp"


int main(int args, char* argv[])
{
    if(args != 3)
    {
        std::cout << "client parameter error!!!" << std::endl;
        exit(CLIENT_PARA_ERRROR);
    }

    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sockfd < 0) exit(-2);

    while(true)
    {
        // sendto
        struct sockaddr_in server;
        memset(&server,0, sizeof(server));
        server.sin_family = AF_INET;
        server.sin_addr.s_addr = inet_addr(argv[1]);
        server.sin_port = htons(std::stoi(argv[2]));

        std::cout << "[lazy_find]#";
        std::string information;
        std::getline(std::cin, information);
        ssize_t n = ::sendto(sockfd, information.c_str(), sizeof(n), 0, (struct sockaddr*)&server, sizeof(server));
        if(n < 0)
        {
            perror("sendto");
            exit(SENDTO_ERROR);
        }
        // recvfrom
        char inbuffer[1024];
        struct sockaddr_in temp;
        socklen_t len = sizeof(temp);
        ssize_t m = ::recvfrom(sockfd, inbuffer, sizeof(inbuffer) - 1, 0, (struct sockaddr*)&temp, &len);
        inbuffer[m] = 0;
        if(m < 0)
        {
            perror("recvfrom");
            exit(RECVFORM_ERROR);
        }
        std::cout << "[lazy_result]#" << inbuffer << std::endl;
        

    }


    return 0;
}

udpserver.hpp

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pragma once

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>
#include <iostream>
#include <functional>
#include "InetAddr.hpp"
#include "Common.hpp"



static const int gsockfd = -1;
static const uint16_t gport = 8888;

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


class udpserver
{

public:
    udpserver(func_t func,int sockfd = gsockfd,uint16_t port = gport)
        : _isrunning(false),_sockfd(sockfd), _port(port),_func(func)
    {
    }

    void Initserver()
    {
        // create sockfd
        _sockfd = socket(AF_INET, SOCK_DGRAM, 0); // 别又int
        if (_sockfd < 0)
        {
            std::cout << "sockfd error" << std::endl;
            exit(SOCKFD_ERROR);
        }
        std::cout << "sockfd success: " << _sockfd << std::endl;

        // server imformation
        struct sockaddr_in server;
        memset(&server, 9, sizeof(server));
        server.sin_family = AF_INET;
        server.sin_port = htons(_port); // htons
        server.sin_addr.s_addr = INADDR_ANY;

        // bind
        socklen_t len = sizeof(server);
        int n = ::bind(_sockfd, (struct sockaddr *)&server, len);
        if (n < 0)
        {
            std::cout << "Bind error" << std::endl;
            exit(BIND_ERROR);
        }
        std::cout << "Bind success" << std::endl;
    }

    void start()
    {
        _isrunning = true;
        while (_isrunning)
        {
            // recvfrom
            char inbuffer[1024];
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            ssize_t n = recvfrom(_sockfd, inbuffer, sizeof(inbuffer) - 1, 0, (struct sockaddr *)&client, &len);
            if (n < 0)
            {
                perror("recvfrom");
                exit(RECVFORM_ERROR);
            }
            // send
            else
            {
                InetAddr addr(client);

                std::string client_info = addr.IP() + std::to_string(addr.Port());
                
                // std::string info = "[lazy_client find]#";
                printf("[%s:%s]find#", addr.IP().c_str(), std::to_string(addr.Port()).c_str());
                std::cout << inbuffer << std::endl;
                // info += inbuffer;
                // std::cout << info << std::endl;

                // 处理业务
                std::string ans = _func(inbuffer);
                
                ssize_t n = sendto(_sockfd, ans.c_str(), ans.size(), 0, (struct sockaddr*)&client, len);
                if(n < 0)
                {
                    std::cout << "sendto error" << std::endl;
                    exit(SENDTO_ERROR);
                }
            }
        }
        _isrunning = false;
    }

    ~udpserver()
    {
        if(_sockfd < 0) ::close(_sockfd);
    }

private:
    uint16_t _port;
    int _sockfd;
    func_t _func;
    /* std::string _serverip;  server端不需要ip */
    bool _isrunning;
};

serverMain.cc

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include "udpserver.hpp"
#include <memory>
#include <functional>
#include "dict.hpp"

int main(int args, char* argv[])
{
    if(args != 2)
    {
        std::cout << "parameter num error!!!" << std::endl;
        exit(SERVER_PARAMETER_ERROR);
    }
    
    int _serverport = std::stoi(argv[1]);

    Dict dict;
    func_t func = std::bind(&Dict::Translate, dict, std::placeholders::_1);

    std::unique_ptr<udpserver> usvr = std::make_unique<udpserver>(func,_serverport); // C++14
    usvr->Initserver();
    usvr->start();

    return 0;
}

感谢阅读!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-04-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
UDP英译汉网络词典
这里我们用UDP实现一个简单的英译汉小词典。我们还是仿照前一篇的UDP编程,将各自的组件封装起来,实现高内聚低耦合。
小灵蛇
2024/09/09
1220
UDP英译汉网络词典
【网络编程】搭建一个简单的UDP通信服务器和客户端
主函数中的代码逻辑分为两部分,第一是主函数逻辑,即创建并运行服务器对象.第二部分是提供服务器数据处理的回调函数,这里提供了三个不同功能的回调函数,分别是字符串大小写转换功能函数,聊天功能函数,简单复读机功能函数,指令执行功能函数.这些回调函数需要在Run服务器的时候当作参数传递给服务器,以便服务器调用这些函数来处理接收到的数据.完整代码如下:
修修修也
2025/03/30
940
【网络编程】搭建一个简单的UDP通信服务器和客户端
网络(TCP)
socket()函数用法详解:创建套接字 - C语言中文网 (biancheng.net)
ljw695
2024/11/21
1240
网络(TCP)
【Linux网络编程】Socket编程--UDP(第一弹):实现客户端和服务器互相发送消息
任何一个UDP服务通信中,都需要有一个int sockfd的文件描述符,按照系统编程中所说,这里打印出来的文件描述符应该是3,因为0,1,2已经被占用了。
南桥
2024/10/20
2190
【Linux网络编程】Socket编程--UDP(第一弹):实现客户端和服务器互相发送消息
UDP简单聊天室创建
服务端仍然沿用我们前面的思想(高内聚低耦合),因此我们用一下上一篇UDP英译汉网络词典的服务端实现(点此查看)。
小灵蛇
2024/09/08
1140
UDP简单聊天室创建
Tcp协议Socket编程
  本次socket编程需要使用到 日志文件,此为具体日志编写过程。以及 线程池,线程池原理比较简单,看注释即可。
用户11029129
2024/11/22
620
Tcp协议Socket编程
【网络】UDP的应用场景
我们可以在服务端udpServer.hpp中设置一个回调函数 _callback,具体的逻辑通过udpServer.cc中由外部进行传入
平凡的人1
2023/10/15
2430
【网络】UDP的应用场景
Udp协议Socket编程
  本次socket编程需要使用到 日志文件,此为具体日志编写过程。以及 线程池,线程池原理比较简单,看注释即可。
用户11029129
2024/11/17
1200
Udp协议Socket编程
【Linux网络编程】Socket编程--UDP:实现服务器接收客服端的消息
<font color= black face="楷体" size=3><center>🌈个人主页:南桥几晴秋
南桥
2024/10/24
1620
【Linux网络编程】Socket编程--UDP:实现服务器接收客服端的消息
【Linux】:Socket编程UDP(EchoServer(聊天)| DictServer(中译英字典)| ChatServer(简单聊天室))
在上篇文章 【Linux】: Socket 编程 里面已经关于 socket 网络编程的前置知识,这里我们就来实际运用一下其 套接字 来实现相关的套接字编程吧
IsLand1314
2025/01/17
840
【Linux】:Socket编程UDP(EchoServer(聊天)| DictServer(中译英字典)| ChatServer(简单聊天室))
【Linux网络编程】Socket编程--TCP:echo server | 多线程远程命令执行
在学习本章之前,先看【Linux网络编程】Socket编程–UDP:实现服务器接收客服端的消息 | DictServer简单的英译汉的网络字典 | 简单聊天室】,里面详细介绍函数的使用方法,小编在这篇文章不再具体介绍。
南桥
2024/11/14
1390
【Linux网络编程】Socket编程--TCP:echo server | 多线程远程命令执行
【计网】从零开始使用UDP进行socket编程 --- 服务端业务实现
上一篇文章中,我们通过UDP协议实现了客户端和服务端的通信:客户端与服务端通信实现
叫我龙翔
2024/09/17
760
【计网】从零开始使用UDP进行socket编程 --- 服务端业务实现
【计网】从零开始使用UDP进行socket编程 --- 客户端与服务端的通信实现
我们了解了网络编程的大概,今天我们就来使用UDP协议来实现客户端与服务端之间的通信过程:
叫我龙翔
2024/09/17
2690
Socket编程---TCP篇
但是,并不是说,TCP就是百利而无一害的。前面说了,TCP还有一个特性---面向字节流,这就导致了,目标主机读取到的内容可能并不是完整的源主机发送的内容。此处来填补这个知识。
小灵蛇
2024/09/07
830
Socket编程---TCP篇
【在Linux世界中追寻伟大的One Piece】Socket编程UDP(续)
枫叶丹
2024/10/31
820
【在Linux世界中追寻伟大的One Piece】Socket编程UDP(续)
Linux__之__基于UDP的Socket编程网络通信
本篇博客旨在使用Linux系统接口进行网络通信, 帮助我们更好的熟悉使用socket套接字网络通信, 学会了socket网络通信, 就能发现所谓网络, 不过都是套路而已, 话不多说, 让我们直接进入代码编写部分.
用户11317877
2025/03/24
1220
Linux__之__基于UDP的Socket编程网络通信
【Linux】用C++实现UDP通信:详解socket编程流程
协议 是计算机或通信系统中,不同实体(如设备、程序、服务等)之间进行交互和通信时,共同遵循的一套规则和标准。它定义了数据的格式、传输方式、错误处理、安全机制等,确保通信双方能够正确理解彼此的信息并完成协作。
用户11305458
2025/04/11
1480
Linux网络套接字
本章将函数介绍和代码编写实战一起使用。 IPv4 的 socket 网络编程,sockaddr_in 中的成员 struct in_addr.sin_addr 表示 32 位 的 IP 地址 但是我们通常用点分十进制的字符串表示 IP 地址,以下函数可以在字符串表示和in_addr 表示之间转换; 字符串转 in_addr 的函数:
有礼貌的灰绅士
2025/04/08
920
Linux网络套接字
【在Linux世界中追寻伟大的One Piece】Socket编程UDP
在网络编程中,当一个进程需要绑定一个网络端口以进行通信时,可以使用INADDR_ANY作为IP地址参数。这样做意味着该端口可以接受来自任何IP地址的连接请求,无论是本地主机还是远程主机。例如,如果服务器有多个网卡(每个网卡上有不同的IP地址),使用INADDR_ANY可以省去确定数据是从服务器上具体哪个网卡/IP地址上面获取的。
枫叶丹
2024/10/24
1340
【Linux】Socket编程—UDP
  上述echo server仅仅是将收到的消息回显给客户端,其实我们还可以在服务器中加一点业务处理,比如翻译功能。
大耳朵土土垚
2025/02/10
2440
【Linux】Socket编程—UDP
推荐阅读
相关推荐
UDP英译汉网络词典
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验