【Linux网络编程】Socket编程--UDP(第一弹):实现客户端和服务器互相发送消息

在这里插入图片描述

🌈个人主页: 南桥几晴秋
🌈C++专栏: 南桥谈C++
🌈C语言专栏: C语言学习系列
🌈Linux学习专栏: 南桥谈Linux
🌈数据结构学习专栏: 数据结构杂谈
🌈数据库学习专栏: 南桥谈MySQL
🌈Qt学习专栏: 南桥谈Qt
🌈菜鸡代码练习: 练习随想记录
🌈git学习: 南桥谈Git

🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈
本科在读菜鸡一枚,指出问题及时改正

文章目录

  • Udp Server
    • socket套接字创建
    • 套接字和IP地址、端口号绑定
    • 读取服务器套接字数据--recvfrom
    • 发送数据--stndto
    • 注意事项
  • UDP Client
  • 完整代码
  • 实例测试

简单的回显服务器和客户端代码

Udp Server

socket套接字创建

#include<sys/types.h>
#include<sys/socket.h>int socket(int domain, int type, int protocol);

在这里插入图片描述

参数说明:

  • int domain:指定协议族
    AF_INET: IPv4 协议
    AF_INET6: IPv6 协议
    AF_UNIX: 本地通信(也称为 UNIX 域套接字)
    在这里插入图片描述

  • int type:指定套接字的类型
    SOCK_STREAM: 提供可靠的、面向连接的字节流(TCP)
    SOCK_DGRAM: 提供不可靠的、无连接的数据报(UDP)
    SOCK_RAW: 提供原始套接字,允许直接访问网络层(通常用于网络监测或自定义协议)
    在这里插入图片描述

  • int protocol:指定所需的协议

  • 返回值:成功时,socket 函数返回一个非负整数,代表新创建的套接字的文件描述符。这个文件描述符可以用于后续的套接字操作(如 bind、listen、accept 等)。
    失败时,返回 -1,并设置 errno 来指示错误原因。
    在这里插入图片描述

在UDP通信中,将前两个参数设置好之后,最后一个参数设置成0即可。

任何一个UDP服务通信中,都需要有一个int sockfd的文件描述符,按照系统编程中所说,这里打印出来的文件描述符应该是3,因为0,1,2已经被占用了。


创建套接字代码:

void InitServer()
{//1.创建套接字  _sockfd=::socket(AF_INET,SOCK_DGRAM,0); //调用系统级的方法if(_sockfd<0){//通信不可能实现,直接退出LOG(FATAL,"socket error\n");exit(SOCKET_ERROR);}LOG(DEBUG,"socket creat success, _sockfd:%d\n",_sockfd); //_socked=3
}

在这里插入图片描述

套接字和IP地址、端口号绑定

网络通信中,客户端和服务器需要有自己的IP地址和端口号,因此需要将套接字和IP地址、端口号绑定。

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    void InitServer(){//1.创建套接字(文件)  _sockfd=::socket(AF_INET,SOCK_DGRAM,0); //调用系统级的方法if(_sockfd<0){//通信不可能实现,直接退出LOG(FATAL,"socket error\n");exit(SOCKET_ERROR);}LOG(DEBUG,"socket creat success, _sockfd:%d\n",_sockfd); //_socked=3//2.bind//(1)先填充本地信息struct sockaddr_in local;memset(&local,0,sizeof(local));local.sin_family=AF_INET;local.sin_port=htons(_localport); //端口号需要从主机转换成网络序列local.sin_addr.s_addr=inet_addr(_localip.c_str());             //用户习惯的是字符串,比如"192.xxx.xxx.xxx"//但是网络中需要4字节ip,需要的是网络序列ip//也就是说这里需要将字符串转换成4字节和网络序列//(2)绑定int n=::bind(_sockfd,(struct sockaddr*)&local,sizeof(local));if(n<0){//绑定失败,不会网络通信LOG(FATAL,"bind error\n");exit(BAND_ERROR);}//绑定成功LOG(DEBUG,"socket bind success\n");}

在这里插入图片描述

  • 定义一个struct sockaddr_in local;结构体用于存储本地地址信息,该对象中有四个字段,如下:
    在这里插入图片描述
    需要对前三个字段进行设置,sin_family 的值和 socket 函数中的 domain 参数保持一致;sin_por是端口信息,由于是在网络中通信,需要将主机转换成网络序列; local.sin_addr.s_addr=inet_addr(_localip.c_str())是将ip地址从主机序列转换成网络序列,但是ip地址用户习惯于字符串形式,即“192.xxx.xxx.xxx”,需要转换成4字节,这里直接使用inet_addr()函数即可。

读取服务器套接字数据–recvfrom

#include <sys/types.h>
#include <sys/socket.h>ssize_t recv(int sockfd, void *buf, size_t len, int flags);ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);

参数解释:

  • sockfd套接字描述符
  • buf: 指向存储接收到数据的缓冲区的指针
  • len: 要接收的字节数,表示缓冲区的大小
  • flags: 接收选项的标志
  • src_addr: 可选参数,指向 sockaddr 结构体的指针,用于存储发送方的地址信息。如果不需要该信息,可以传入 NULL
  • addrlen: 可选参数,指向一个 socklen_t 类型的变量,表示 src_addr 指向的结构的大小。调用后,该变量将被更新为实际的地址长度。

发送数据–stndto

#include <sys/types.h>
#include <sys/socket.h>ssize_t send(int sockfd, const void *buf, size_t len, int flags);ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
  • dest_addr:指向目标地址的指针,通常是 sockaddr 结构体的指针,表示数据将要发送到的地址。如果目标是 UDP 套接字,必须指定目标地址。
  • addrlen:指向一个 socklen_t 类型的变量,表示 dest_addr 指向的结构的大小。这个参数在调用时需要正确设置,调用后该变量会被更新为实际的地址长度。

void Start()
{_isrunning=true;char inbuffer[1024];while (_isrunning){struct sockaddr_in peer;socklen_t len=sizeof(peer);ssize_t n=recvfrom(_sockfd,inbuffer,sizeof(inbuffer)-1,0,(struct sockaddr*)&peer,&len);if(n>0){inbuffer[n]=0;std::string echo_string="[udp_server echo] #";echo_string+=inbuffer;sendto(_sockfd,echo_string.c_str(),echo_string.size(),0,(struct sockaddr*)&peer,len);}}}

注意事项

云服务器上禁止绑定自己的公网:
在这里插入图片描述

可以绑定内网,但是都不到信息,因为不会在公网公布:
在这里插入图片描述

在云服务上,绑定IP地址一般绑定为0,这样云服务器绑定了任意IP:
在这里插入图片描述

服务器端进程任意IP地址绑定:

local.sin_addr.s_addr=INADDR_ANY;

在这里插入图片描述

UDP Client

和服务器有所不同, 客户端的进程很多,但是端口号只能和一个进程绑定,可能出现两个进程绑定同一个端口号,会出现冲突无法运行。为了解决这一问题,客户端的端口号一般不让用户设定,而是让客户端操作所在的操作系统随机选择一个端口号。客户端的端口号具体是多少不重要,只要能标记和别的进程不一样即可。

客户端需要绑定自己的IP地址和端口,但是不需要显示绑定自己的IP地址和端口。客户端在首次向服务器发送数据的时候,系统会自动给客户端绑定它自己的IP和端口。

#include <iostream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>// 客户端需要先知道服务器ip地址和端口号int main(int argc, char *argv[])
{if (argc != 3){std::cerr << "Usage: " << argv[0] << " server-ip server-port" << std::endl;exit(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 << "create socket error" << std::endl;exit(1);}// client 不需要显示绑定自己的IP和端口,但是需要绑定自己的IP和端口struct 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());while (1){std::string line;std::cout << "Please Enter# ";std::getline(std::cin, line);int n = sendto(sockfd, line.c_str(), line.size(), 0, (sockaddr *)&server, sizeof(server));if (n > 0){struct sockaddr_in temp;socklen_t len = sizeof(temp);char buffer[1024];int m = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, (sockaddr *)&temp, &len);if (m > 0){buffer[m] = 0;std::cout << buffer << std::endl;}else{break;}}else{break;}}::close(sockfd);return 0;
}

完整代码

UdpServer.hpp

#pragma once#include<iostream>
#include<cstring>
#include<unistd.h>
#include<string>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include"nocopy.hpp"
#include"Log.hpp"using namespace log_ns;static const int gsockfd=-1;
static const uint16_t glocalport=8888;enum
{SOCKET_ERROR=1,BAND_ERROR
};class UdpServer:public nocopy
{
public:UdpServer(uint16_t localport=glocalport):_sockfd(gsockfd),_localport(localport),_isrunning(false){}void InitServer(){//1.创建套接字(文件)  _sockfd=::socket(AF_INET,SOCK_DGRAM,0); //调用系统级的方法if(_sockfd<0){//通信不可能实现,直接退出LOG(FATAL,"socket error\n");exit(SOCKET_ERROR);}LOG(DEBUG,"socket creat success, _sockfd:%d\n",_sockfd); //_socked=3//2.bind//(1)先填充本地信息struct sockaddr_in local;memset(&local,0,sizeof(local));local.sin_family=AF_INET;local.sin_port=htons(_localport); //端口号需要从主机转换成网络序列/*local.sin_addr.s_addr=inet_addr(_localip.c_str());             //用户习惯的是字符串,比如"192.xxx.xxx.xxx"//但是网络中需要4字节ip,需要的是网络序列ip//也就是说这里需要将字符串转换成4字节和网络序列*/local.sin_addr.s_addr=INADDR_ANY;//(2)绑定int n=::bind(_sockfd,(struct sockaddr*)&local,sizeof(local));if(n<0){//绑定失败,不会网络通信LOG(FATAL,"bind error\n");exit(BAND_ERROR);}//绑定成功LOG(DEBUG,"socket bind success\n");}void Start(){_isrunning=true;char inbuffer[1024];while (_isrunning){struct sockaddr_in peer;socklen_t len=sizeof(peer);ssize_t n=recvfrom(_sockfd,inbuffer,sizeof(inbuffer)-1,0,(struct sockaddr*)&peer,&len);if(n>0){inbuffer[n]=0;std::cout<<"client say# "<<inbuffer<<std::endl;std::string echo_string="[udp_server echo] #";echo_string+=inbuffer;sendto(_sockfd,echo_string.c_str(),echo_string.size(),0,(struct sockaddr*)&peer,len);}else{std::cout<<"recvfrom : error "<<std::endl;}}}~UdpServer(){if(_sockfd>gsockfd)::close(_sockfd);}private:int _sockfd;    uint16_t _localport; //服务器的端口号bool _isrunning;
};

UdpServerMain.cc

#include"UdpServer.hpp"
#include<memory>int main(int argc, char *argv[])
{if (argc != 2){std::cerr << "Usage: " << argv[0] << " local-port" << std::endl;exit(0);}uint16_t port = std::stoi(argv[1]);EnableScreen();std::unique_ptr<UdpServer> usvr=std::make_unique<UdpServer>(port); //C++14标准usvr->InitServer();usvr->Start();return 0;
}

UdpClientMain.cc

#include <iostream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>// 客户端需要先知道服务器ip地址和端口号int main(int argc, char *argv[])
{if (argc != 3){std::cerr << "Usage: " << argv[0] << " server-ip server-port" << std::endl;exit(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 << "create socket error" << std::endl;exit(1);}// client 不需要显示绑定自己的IP和端口,但是需要绑定自己的IP和端口struct 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());while (1){std::string line;std::cout << "Please Enter# ";std::getline(std::cin, line);int n = sendto(sockfd, line.c_str(), line.size(), 0, (sockaddr *)&server, sizeof(server));if (n > 0){struct sockaddr_in temp;socklen_t len = sizeof(temp);char buffer[1024];int m = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, (sockaddr *)&temp, &len);if (m > 0){buffer[m] = 0;std::cout << buffer << std::endl;}else{break;}}else{break;}}::close(sockfd);return 0;
}

实例测试

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

.Net自动更新程序GeneralUpdate,适用于wpf,winfrom,控制台应用

GeneralUpdate是基于.net framwork4.5.2开发的一款&#xff08;c/s应用&#xff09;自动升级程序。 第一个版本叫Autoupdate 有人会奇怪为什么会改名称&#xff0c;稍微解释一下是因为在nuget上有重名的项目再者就是新版本更新功能不仅限于wpf程序的更新。 将更新的核心部分抽…

《Knowledge Perceived Multi-modal Pretraining in E-commerce》中文校对版

文章中文化系列目录 文章目录 文章中文化系列目录摘要CCS概念&#xff1a;关键词&#xff1a;1 引言2 相关工作2.1 多模态预训练2.2 知识图谱增强的预训练模型 3 方法3.1 模态编码层3.1.1 图像初始特征3.1.2 文本初始特征3.1.3 知识的表面形式特征 3.2 模态交互层3.2.1 图像模态…

day02 -- docker

1.docker的介绍 Docker 是一个开源的应用容器引擎&#xff0c;基于 Go语言 并遵从 Apache2.0 协议开源。Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中&#xff0c;然后发布到任何流行的 Linux 机器上&#xff0c;也可以实现虚拟化。容器是完全使…

填充与步幅

一个3x3的卷积核对6X6的图像进行卷积&#xff0c;得到一个4x4的图像 此时&#xff0c;生成图像长或宽 ln-f1 使用过滤器对图像进行卷积出现的问题有&#xff1a; 每次卷积后图像都会变小&#xff0c;当网络过深的时候&#xff0c;就会遗失许多像素 过滤器对边缘像素访问仅一…

基于C#开发游戏辅助工具的Windows底层相关方法详解

开发游戏辅助工具通常需要深入了解Windows操作系统的底层机制&#xff0c;以及如何与游戏进程进行有效交互。本文将基于C#语言&#xff0c;从Windows底层方法的角度来详细讲解开发游戏辅助工具的相关技术和概念。 一、游戏辅助工具的基本概述 游戏辅助工具&#xff0c;通常被称…

网络学习笔记

一、网络的结构与功能 网络的鲁棒性与抗毁性 如果在移走少量节点后网络中的绝大部分节点仍然是连通的&#xff0c;那么就该网络的连通性对节点故障具有鲁棒性 网络上的动力学 动力系统&#xff1a;自旋、振子或混沌的同步、可激发系统 传播过程&#xff1a;信息传播与拥堵…

git命令使用一览【自用】

git常见操作&#xff1a; git initgit remote add master【分支名字】 gitgits.xxxxx【仓库中获取的ssh链接或者http协议的链接】检查远程仓库是否链接成功。 git remote -v出现以下画面就可以git pull,git push了

可以与 FastAPI 不分伯仲的 Python 著名的 Web 框架

正如你所理解的&#xff0c;任何领域都不可能停止进步&#xff0c;不断使用相同的工具意味着不思进取。这一点在信息技术领域&#xff0c;尤其是网络开发行业非常明显。 关于网络框架&#xff0c;不论是 Django 和 Flask 等传统框架还是 Python 的新型高级框架&#xff0c;一直…

Semantic Kernel进阶:将ChatCompletion(聊天完成)服务添加到你的AI项目(三)

文章目录 Semantic Kernel进阶&#xff1a;将聊天完成服务添加到你的AI项目一、引言二、聊天完成服务的重要性三、基本介绍3.1 创建聊天完成服务3.2 依赖注入方式3.3 创建独立的服务实例 四、实战4.1 检索聊天完成服务4.2 使用聊天完成服务4.2.1 非流式4.2.2 流式 4.3 完整代码…

Mybatis多对一查询的配置及两种方法的使用示例对比以及Mybatis一对多查询两种方法使用示例及对比

一、Mybatis多对一查询的配置及两种方法的使用示例对比 为了试验Mybatis多对一的查询&#xff0c;我们先在数据库中建两个表&#xff0c;一个城市表&#xff0c;一个市区表&#xff0c;一个城市有多个区是一个一对多的关系&#xff1b;多个区对应一个城市是一个多对一的关系。建…

第五届光学与图像处理国际学术会议(ICOIP 2025)征稿中版面有限!

第五届光学与图像处理国际学术会议&#xff08;ICOIP 2025&#xff09; 2025 5th International Conference on Optics and Image Processing (ICOIP 2025&#xff09; 重要信息 时间地点&#xff1a;2025年4月25-27日丨中国西安 截稿日期&#xff1a;2024年12月16日23:59 …

vue3项目使用百度地图实现地图选择功能代码封装(开箱即用)

vue3项目使用百度地图实现地图选择功能代码封装方案(开箱即用) <template><div class="bmapgl">

【软件测试】JUnit

Junit 是一个用于 Java 编程语言的单元测试框架&#xff0c;Selenium是自动化测试框架&#xff0c;专门用于Web测试 本篇博客介绍 Junit5 文章目录 Junit 使用语法注解参数执行顺序断言测试套件 Junit 使用 本篇博客使用 Idea集成开发环境 首先&#xff0c;创建新项目&#…

一图解千言,了解常见的流程图类型及其作用

在企业管理、软件研发过程中&#xff0c;经常会需要进行各种业务流程梳理&#xff0c;而流程图就是梳理业务时必要的手段&#xff0c;同时也是梳理的产出。但在不同的情况下适用的流程图又不尽相同。 本文我们就一起来总结一下8 种最常见的流程图类型 数据流程图 数据流程图&…

【CTF-SHOW】Web入门 Web14 【editor泄露-详】【var/www/html目录-详】

editor泄露问题通常出现在涉及文件编辑器或脚本编辑器的题目中&#xff0c;尤其是在Web安全或Pwn&#xff08;系统漏洞挖掘&#xff09;类别中。editor泄露的本质是由于系统未能妥善处理临时文件、编辑历史或进程信息&#xff0c;导致攻击者可以通过某种途径获取正在编辑的敏感…

javaweb-mybatis之动态sql

(1).if标签 编写好方法之后&#xff0c;选中方法名&#xff0c;alt回车&#xff0c;选第一个generate statement快捷生成xml里的标签 (2).foreach标签 用于批量删除 (3)sql和include标签

架构师面试:怎样规划公司的监控架构?

大家好&#xff0c;我是君哥。 监控系统在科技公司非常重要&#xff0c;它可以让运维人员和研发人员提前发现问题、定位问题&#xff0c;进而解决问题。 在我们实际工作中&#xff0c;使用的监控往往五花八门&#xff0c;比较混乱&#xff0c;今天来聊一聊怎么规划公司的监控…

QT开发:深入掌握 QtGui 和 QtWidgets 布局管理:QVBoxLayout、QHBoxLayout 和 QGridLayout 的高级应用

目录 引言 1. QVBoxLayout&#xff1a;垂直布局管理器 基本功能 创建 QVBoxLayout 添加控件 添加控件和设置对齐方式 设置对齐方式 示例代码与详解 2. QHBoxLayout&#xff1a;水平布局管理器 基本功能 创建 QHBoxLayout 添加控件 添加控件和设置对齐方式 设置对齐…

【CTF刷题9】2024.10.19

[MoeCTF 2021]babyRCE 考点&#xff1a;关键词过滤&#xff08;绕过方法参考往期博客&#xff09; 来源&#xff1a;nssctf <?php$rce $_GET[rce]; if (isset($rce)) {if (!preg_match("/cat|more|less|head|tac|tail|nl|od|vi|vim|sort|flag| |\;|[0-9]|\*|\|\%|\&g…

京存助力北京某电力研究所数据采集

北京某电力研究所已建成了一套以光纤为主&#xff0c;卫星、载波、微波等多种通信方式共存&#xff0c;分层级的电力专用的网络通信架构体系。随着用电、配电对网络的要求提高&#xff0c;以及终端通信入网的迅速发展&#xff0c;迫切地需要高效的通信管理系统来应对大规模、复…