以线程完成并发的UDP服务端
网络(九)并发的UDP服务端 以线程完成功能
客户端
// todo UDP发送端
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>#define LOGIN_SUCCESS 1
#define LOGIN_FAIL 0
//?发送数据
//?@param fd 套接字描述符
//?@param addr 目标地址
//?@param addrlen 地址长度
void send_data(int fd, struct sockaddr_in * addr , socklen_t addrlen);void login(int fd, struct sockaddr_in * addr ,struct sockaddr_in * new_addr , socklen_t new_addrlen);//命令行参数 ip port
int main(int argc, char *argv[] ){
// if(argc!= 3){
// printf("Usage: %s ip port\n", argv[0]);
// exit(EXIT_FAILURE);
// }//!通过socket函数创建套接字//!@param domain 协议族,AF_INET表示IPv4协议族//!@param type 套接字类型,SOCK_DGRAM表示UDP套接字//!@param protocol 协议,一般为0 让系统⾃动识别//!@return 成功返回套接字描述符,失败返回-1int fd = socket(AF_INET, SOCK_DGRAM, 0);if(fd == -1){ //创建套接字失败perror("socket err");exit(EXIT_FAILURE);}//准备接收消息的地址/* struct sockaddr_in {short int sin_family; // 地址族 AF_INETunsigned short int sin_port; // 端口号struct in_addr sin_addr;// IP地址unsigned char sin_zero[8]; // 填充字节 为了对齐sockaddr};*/struct sockaddr_in addr;memset(&addr, 0, sizeof(addr));addr.sin_family=AF_INET;addr.sin_port=htons(8083);//htons函数将主机字节序转换为网络字节序//addr.sin_addr.s_addr=inet_addr("192.168.74.1");//inet_addr()将点分十进制IP地址转换为网络字节序IP地址//inet_aton()将点分十进制IP地址转换为网络字节序IP地址//@param ip 字符串形式的IP地址//@param in_addr 结构体变量,用于存储IP地址int ret=inet_aton("172.17.140.183", &addr.sin_addr); // 成功返回⾮0,失败返回0if(ret == 0){perror("inet_aton err");exit(EXIT_FAILURE);}printf("ip == %d\n",addr.sin_addr.s_addr);//inet_ntoa()将网络字节序IP地址转换为点分十进制IP地址//char *ip=inet_ntoa(addr.sin_addr); // 成功返回⾮0,失败返回0//printf("ip == %s\n",ip);//获取 和服务端的新建的子进程通信struct sockaddr_in new_addr;login(fd, &addr, &new_addr, sizeof(new_addr));//与新的子进程通信send_data(fd, &new_addr, sizeof(new_addr));return 0;
}//!发送数据
//!@param fd 套接字描述符
//!@param addr 目标地址
//!@param addrlen 地址长度
void send_data(int fd, struct sockaddr_in * addr , socklen_t addrlen){while (1){int n = 0;//返回发送的字节数char buf[1024] = {0};printf("请输入要发送的消息:");fgets(buf, 1024, stdin);//!发送数据//!@param fd 套接字描述符//!@param buf 发送缓冲区//!@param len 发送缓冲区长度//!@param flags 发送标志 0 表示默认操作//!@param addr 目标地址//!@param addrlen 地址长度//!@return 成功返回发送的字节数,失败返回-1n= sendto(fd, buf, strlen(buf), 0, (struct sockaddr *)addr, addrlen);if(n == -1){perror("sendto err");exit(EXIT_FAILURE);}if(strncmp(buf, "exit",4) == 0){break;}}}void login(int fd, struct sockaddr_in * addr ,struct sockaddr_in * new_addr , socklen_t addrlen){char login_status=LITTLE_ENDIAN;while (1){int n = 0;//返回发送的字节数char buf[1024] = {0};printf("请输入要发送的消息:");fgets(buf, 1024, stdin);n= sendto(fd, buf, strlen(buf), 0, (struct sockaddr *)addr, addrlen);if(n == -1){perror("sendto err");exit(EXIT_FAILURE);}//接收消息服务器的响应n= recvfrom(fd, &login_status, sizeof(login_status), 0, (struct sockaddr *)new_addr, &addrlen);if(n == -1){perror("recvfrom err");exit(EXIT_FAILURE);}if(login_status == LOGIN_SUCCESS){printf("登录成功\n");printf("新的子进程的地址为:%s:%d\n",inet_ntoa(new_addr->sin_addr),ntohs(new_addr->sin_port));break;}else if(login_status == LOGIN_FAIL){printf("登录失败\n");continue;}if(strncmp(buf, "exit",4) == 0){break;}}}
服务端
服务端创建主线程,接收客户端的请求,创建新的子线程,
子线程完成后续交互,子线程中创建新的套接字,返回给客户端,后续交互将在新的套接字中完成.
将子线程分离,线程运行结束将由系统回收资源
// todo UDP服务器端程序
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <pthread.h>
#define LOGIN_SUCCESS 1
#define LOGIN_FAIL 0//接收数据
void recv_data(int sockfd);
void *pthread_todo(void *arg);//初始化套接字
int init_socket(char *ip, char* port);int TheLogin(char *ip, char * port);//定义结构体为子线程传递参数
struct thread_arg {char *ip;unsigned char login_status;struct sockaddr_in thread_addr;//客户端的地址
}thread_arg;int main(int argc, char *argv[]){//验证int new_sockfd = TheLogin("172.17.140.183", "8083");//接收数据//由子线程完成//关闭套接字close(new_sockfd);return 0;
}//接收数据
void recv_data(int sockfd) {struct sockaddr_in client_addr;//客户端的地址int client_addr_len = sizeof(client_addr);while(1) {char recv_buf[1024]={0};//接收数据//*@param sockfd 套接字描述符//*@param buf 接收缓冲区//*@param len 接收缓冲区长度//*@param flags 接收标志//*@param src_addr 发送方地址//*@param addrlen 发送方地址长度//*@return 成功返回接收到的字节数,失败返回-1int ret = recvfrom(sockfd, recv_buf, sizeof(recv_buf), 0, (struct sockaddr *) &client_addr, &client_addr_len);if (ret == -1) {perror("recvfrom err");exit(EXIT_FAILURE);}//打印接收到的信息char *ip_str = inet_ntoa(client_addr.sin_addr);//将网络字节序IP地址转换为点分十进制IP地址int port = ntohs(client_addr.sin_port); //将网络字节序端口号转换为主机字节序端口号printf("接收到来自%s:%d的数据:%s\n", ip_str, port, recv_buf);if(strncmp(recv_buf, "exit", 4) == 0){//退出程序break;}}close(sockfd);return;
}int init_socket(char *ip,char *port){//!通过socket函数创建套接字//!@param domain 协议族,AF_INET表示IPv4协议族//!@param type 套接字类型,SOCK_DGRAM表示UDP套接字//!@param protocol 协议,一般为0 让系统⾃动识别//!@return 成功返回套接字描述符,失败返回-1int fd = socket(AF_INET, SOCK_DGRAM, 0);if(fd == -1){ //创建套接字失败perror("socket err");exit(EXIT_FAILURE);}//准备服务器地址/* struct sockaddr_in {short int sin_family; // 地址族 AF_INETunsigned short int sin_port; // 端口号struct in_addr sin_addr;// IP地址unsigned char sin_zero[8]; // 填充字节 为了对齐sockaddr};*/struct sockaddr_in addr;memset(&addr, 0, sizeof(addr));addr.sin_family=AF_INET;addr.sin_port=htons(atoi(port));//htons函数将主机字节序转换为网络字节序//inet_aton()将点分十进制IP地址转换为网络字节序IP地址//*@param ip 字符串形式的IP地址//*@param in_addr 结构体变量,用于存储IP地址int ret=inet_aton(ip, &addr.sin_addr); // 成功返回⾮0,失败返回0if(ret == 0){perror("inet_aton err");exit(EXIT_FAILURE);}//!绑定套接字到服务器地址//!@param sockfd 套接字描述符//!@param addr 服务器地址//!@param addrlen 服务器地址长度//!@return 成功返回0,失败返回-1int ret2 = bind(fd, (struct sockaddr*)&addr, sizeof(addr));if(ret2 == -1){perror("bind err");exit(EXIT_FAILURE);}return fd;
}int TheLogin(char *ip, char *port){unsigned char login_status;int new_sockfd;//初始化套接字int sockfd = init_socket(ip, port);//线程创建pthread_t recv_thread;struct sockaddr_in client_addr;//客户端的地址int client_addr_len = sizeof(client_addr);while(1) {char recv_buf[1024]={0};int ret = recvfrom(sockfd, recv_buf, sizeof(recv_buf), 0, (struct sockaddr *) &client_addr, &client_addr_len);if (ret == -1) {perror("recvfrom err");exit(EXIT_FAILURE);}//打印接收到的信息char *ip_str = inet_ntoa(client_addr.sin_addr);//将网络字节序IP地址转换为点分十进制IP地址int port = ntohs(client_addr.sin_port); //将网络字节序端口号转换为主机字节序端口号printf("接收到来自%s:%d的数据:%s\n", ip_str, port, recv_buf);//登录验证//判断是否为登录请求login_status = ( strncmp(recv_buf, "login",5)==0 ? LOGIN_SUCCESS: LOGIN_FAIL ) ;if(login_status == LOGIN_SUCCESS){//使用子线程完成后续交互struct thread_arg pack;pack.ip = ip;pack.login_status = login_status;pack.thread_addr = client_addr;//创建子线程pthread_create(&recv_thread, NULL, pthread_todo, &pack);printf("子线程创建成功\n");} else{//回传失败消息sendto(sockfd, &login_status, sizeof(login_status), 0, (struct sockaddr *) &client_addr, client_addr_len);}//将新建的线程设置为分离状态pthread_detach(recv_thread);printf("子线程分离成功\n");}}void *pthread_todo(void *arg){//子线程函数struct thread_arg *pack = (struct thread_arg*)arg;//创建新的套接字文件描述符int new_sockfd = init_socket(pack->ip, "0");printf("子线程创建新的套接字文件描述符:%d\n", new_sockfd);sendto(new_sockfd, &pack->login_status, sizeof(pack->login_status), 0,\(struct sockaddr *) &pack->thread_addr, sizeof(pack->thread_addr));//接收数据recv_data(new_sockfd);pthread_exit(NULL);}
相关文章:

以线程完成并发的UDP服务端
网络(九)并发的UDP服务端 以线程完成功能 客户端 // todo UDP发送端 #include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/types.h> #include <stdlib.h> #include <string.h…...

linux c 特殊字符分割
/* * brief: 根据split_symbol分割字符串 * param: str为要分割的字符串,split_symbol是分隔符 * return:返回garray的指针数组,如果返回非空需要自己处理释放 */ GPtrArray_autoptr char_sz_spilt(pchar* str, pchar split_symbol) {if (NUL…...

搭建本地私有知识问答系统:MaxKB + Ollama + Llama3 (wsl网络代理配置、MaxKB-API访问配置)
目录 搭建本地私有知识问答系统:MaxKB、Ollama 和 Llama3 实现指南引言MaxKB+Ollama+Llama 3 Start buildingMaxKB 简介:1.1、docker部署 MaxKB(方法一)1.1.1、启用wls或是开启Hyper使用 WSL 2 的优势1.1.2、安装docker1.1.3、docker部署 MaxKB (Max Knowledge Base)MaxKB …...

谷粒商城实战笔记-65-商品服务-API-品牌管理-表单校验自定义校验器
文章目录 1,el-form品牌logo图片自定义显示2,重新导入和注册element-ui组件3,修改brand-add-or-update.vue控件的表单校验规则firstLetter 校验规则sort 校验规则 1,el-form品牌logo图片自定义显示 为了在品牌列表中自定义显示品…...

学好C++之——命名空间
c开始学习之时,你不可避免会遇到一个新朋友,那就是——namespace(命名空间)。 那么这篇文章就来为你解决这个小麻烦喽~ 目录 1.namespace存在的意义 2.namespace的定义 3.namespace的使用 1.namespace存在的意义 在C中&#…...

pytorch lightning报错all tensors to be on the same device
RuntimeError: Expected all tensors to be on the same device, but found at least two devices, cuda:0 and cpu! 修改指定为gpu trainer pl.Trainer(max_epochstrain_params.iterations, loggertb_logger,acceleratorgpu, devices1)...

Redis中的哨兵(Sentinel)
上篇文章我们讲述了Redis中的主从复制(Redis分布式系统中的主从复制-CSDN博客),本篇文章针对主从复制中的问题引出Redis中的哨兵,希望本篇文章会对你有所帮助。 文章目录 一、引入哨兵机制 二、基本概念 三、主从复制的问题 四、哨…...

产业创新研究杂志产业创新研究杂志社产业创新研究编辑部2024年第12期目录
高质量发展 如何在新一轮产业链变革中平稳应对挑战 王宏利; 1-3《产业创新研究》投稿:cnqikantg126.com 基于ERGM的城市间绿色低碳技术专利转让网络结构及演化研究 吕彦朋;姜军;张宁; 4-6 数字基础设施建设对城市FDI的影响——基于“宽带中国”试点政策…...

网闸(Network Gatekeeper或Security Gateway)
本心、输入输出、结果 文章目录 网闸(Network Gatekeeper或Security Gateway)前言网闸主要功能网闸工作原理网闸使用场景网闸网闸(Network Gatekeeper或Security Gateway) 编辑 | 简简单单 Online zuozuo 地址 | https://blog.csdn.net/qq_15071263 如果觉得本文对你有帮助…...

C#中的字符串
String 在实例方法中string虽然传入的是引用类型 但是修改string 并不是修改原来堆里面的值 而是又重新创建一个堆值 用来然后用方法内的变量指向新的堆值 C# 中的字符串(string 类型)提供了许多有用的方法来处理字符串数据。以下是一些常用的字符…...

docker安装部署elasticsearch7.15.2
docker安装部署elasticsearch7.15.2 1.拉取es镜像 docker pull docker.elastic.co/elasticsearch/elasticsearch:7.15.2如果不想下载或者镜像拉去太慢可以直接下载文章上面的镜像压缩包 使用镜像解压命令 docker load -i elasticsearch-7-15-2.tar如下图所示就表示镜像解压成…...

Symfony 入门指南:快速安装与基础配置
Symfony 入门指南:快速安装与基础配置 Symfony 是一个强大而灵活的 PHP 框架,广泛应用于构建现代 Web 应用程序。本指南将带您一步一步地了解如何快速安装 Symfony,并完成基本配置,以便您能够开始使用这个强大的框架。 目录 引…...

3.3V升压至5V的AH6922芯片:高效能的SOP8封装解决方案
# 3.3V升压至5V的AH6922芯片:高效能的SOP8封装解决方案 在当今快速发展的电子设备领域,对于电源管理的需求日益增长。特别是对于便携式产品和手持设备,一个高效、稳定且体积小巧的升压解决方案变得至关重要。本文将介绍一款专为这些需求设计…...

赋能未来教育,3DCAT助力深圳鹏程技师学院打造5G+XR实训室
随着国家对教育行业的重视,实训室建设已成为推动教育现代化的关键。《教育信息化2.0行动计划》、《职业教育示范性虚拟仿真实训基地建设指南》等政策文件,明确指出了加强虚拟仿真实训教学环境建设的重要性。 在这一大背景下,教育行业对于实训…...

力扣141环形链表问题|快慢指针算法详细推理,判断链表是否有环|龟兔赛跑算法
做题链接 目录 前言: 一、算法推导: 1.假设有环并且一定会相遇,那么一定是在环内相遇,且是快指针追上慢指针。 2.有环就一定会相遇吗?快指针是每次跳两步,有没有可能把慢指针跳过去? 3.那一定…...

React 常见的报错及解决方法
1、Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons(无效的钩子调用。钩子只能在函数组件的内部调用。这可能是由于以下原因之一) 原因&#x…...

更新服务器nginx 1.26.1版本
今天在官网下载了nginx1的1.26.1版本,使用gpt的脚本想直接覆盖安装,脚本如下 #!/bin/bash# 设置变量 NGINX_VERSION"1.26.1" TAR_FILE"nginx-$NGINX_VERSION.tar.gz" SRC_DIR"nginx-$NGINX_VERSION"# 检查是否存在tar包 …...

JAVA代码审计JAVA0基础学习(需要WEB基础知识)DAY2
JAVA 在 SQL执行当中 分为3种写法: JDBC注入分析 Mybatis注入分析 Hibernate注入分析 JDBC 模式不安全JAVA代码示例部分特征 定义了一个 sql 参数 直接让用户填入id的内容 一个最简单的SQL语句就被执行了 使用安全语句却并没有被执行 Mybatis: #…...

SpringBoot整合elasticsearch-java
一、依赖 系统使用的是ElasticSearch8.2.0 <dependency><groupId>co.elastic.clients</groupId><artifactId>elasticsearch-java</artifactId><version>8.1.0</version> </dependency> 二、配置 1、yml文件配置 elastics…...

网络服务与应用
一、 文件传输 FTP 1、FTP采用典型的C/S架构(即服务器端和客户端模型),客户端与服务器端建立TCP连接之后即可实现文件的上传、下载。 2、FTP传输过程 1)、主动模式(POST):入站连接 2&#x…...

Git项目如何配置,如何上传至GitHub
Git项目配置并上传至GitHub的详细步骤如下: 一、准备工作 创建GitHub账号: 访问GitHub官网,点击“Sign up”注册新账号。填写相关信息,包括用户名、邮箱和密码,完成账号创建。安装Git客户端: 访问Git官网…...

Python教程(一):环境搭建及PyCharm安装
目录 引言1. Python简介1.1 编译型语言 VS 解释型语言 2. Python的独特之处3. Python应用全览4. Python版本及区别5. 环境搭建5.1 安装Python: 6. 开发工具(IDE)6.1 PyCharm安装教程6.2 永久使用教程 7. 编写第一个Hello World结语 引言 在当…...

神经网络与注意力机制的权重学习对比:公式探索
神经网络与注意力机制的权重学习对比:公式探索 注意力机制与神经网络权重学习的核心差异 在探讨神经网络与注意力机制的权重学习时,一个核心差异在于它们如何处理输入数据的权重。神经网络通常通过反向传播算法学习权重,而注意力机制则通过学…...

C语言------指针讲解(3)
一、字符指针 在指针中,我们知道有一类指针类型为字符指针char*; int main() {char ch w;char* pc &ch;*pc w;return 0; } 还有一种使用方式如下: 上述代码中,本质是把hello的首字符的地址放到了pstr中。即把一个常量字符串的首字符…...

博客建站 - 常用的公共DNS服务器
国内公共DNS服务 服务器名称首选DNS服务备用DNS服务114 DNS114.114.114.114114.114.115.115阿里 DNS223.5.5.5223.6.6.6腾讯云公共DNS119.29.29.29182.254.116.116百度公共DNS180.76.76.76110.242.68.68 国外公共DNS服务 服务器名称首选DNS服务备用DNS服务备注Google DNS8.8…...

用Redisson的RMap做一个简单的购物车示例
RMap是Redisson提供的一个高级数据结构,它封装了Redis中的Hash数据类型,提供了一个类似Java HashMap的接口。RMap非常适合在需要分布式共享的键值对集合场景中使用,以下是一些典型的应用场景: 分布式缓存: RMap可以用作…...

「12月·长沙」第四届机器人、自动化与智能控制国际会议(ICRAIC 2024)
随着科技的飞速发展,智能机器人在当今社会的重要性愈发凸显。从制造业的自动化生产线,到医疗领域的手术机器人,再到家庭生活中的智能助手,机器人与人工智能的融合正在改变着我们的生产和生活方式。第四届机器人、自动化与智能控制…...

传神社区|数据集合集第7期|法律NLP数据集合集
自从ChatGPT等大型语言模型(Large Language Model, LLM)出现以来,其类通用人工智能(AGI)能力引发了自然语言处理(NLP)领域的新一轮研究和应用浪潮。尤其是ChatGLM、LLaMA等普通开发者都能运行的…...

完美解决Ubuntu的MySQL临时文件夹修改调整
打开终端,输入以下命令 $ sudo -i # 切换root用户 $ systemctl stop mysql.service $ mkdir /home/tmp $ chown root:root /home/tmp $ chmod 1777 /home/tmp $ gedit /etc/mysql/mysql.conf.d/mysqld.cnf以上最后一条命令执行完后,在打开的mysqld.cnf文…...

shell基础编程
初始shell 程序 语言 编程 ---------------------------------- 语言 自然语言:汉语、英语 计算机语言:c语言、c、(java php python go shell) 编译型语言 c c java 解释型语言 php python bash 编译型语言:编译型语言的首先将源代码编译生成机器语言,再由机…...