以进程完成并发的UDP服务端

网络(八)并发的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;}}}

多进程 处理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>
#include <signal.h>
#include <sys/wait.h>#define LOGIN_SUCCESS 1
#define LOGIN_FAIL 0void todo(int signum){printf("收到信号%d\n",signum);waitpid(-1, NULL, WNOHANG);
}//接收数据
void recv_data(int sockfd);//初始化套接字
int  init_socket(char *ip, char* port);int TheLogin(char *ip, char * port);int main(int argc, char *argv[]){//处理僵死的子进程signal(SIGCHLD, todo);//验证int new_sockfd = TheLogin("172.17.140.183", "8083");//接收数据recv_data(new_sockfd);//关闭套接字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);exit(EXIT_SUCCESS);
}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);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){//使用子进程完成后续的交互int pid = fork();if(pid == -1){perror("fork err");exit(EXIT_FAILURE);}else if(pid == 0){printf("开始了新的进程\n");//子进程将关闭父进程的套接字close(sockfd);//子进程使用新的套接字完成后续的交互//使用0号,系统将自动分配一个可用端口号new_sockfd = init_socket(ip, "0");printf("新的套接字文件描述符:%d\n", new_sockfd);//子进程通过新的端口 发送成功消息sendto(new_sockfd, &login_status, sizeof(login_status), 0, (struct sockaddr *) &client_addr, client_addr_len);break;}} else{//回传失败消息sendto(sockfd, &login_status, sizeof(login_status), 0, (struct sockaddr *) &client_addr, client_addr_len);}}//返回新的套接字return new_sockfd;
}

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

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

相关文章

【Python机器学习】k-近邻算法简单实践——改进约会网站的配对效果

需求背景&#xff1a; XX一直使用约会网站寻找适合自己的约会对象&#xff0c;ta会把人分为3种类型&#xff1a; 不喜欢、魅力一般、非常有魅力 对人分类轴&#xff0c;发现了对象样本的以下3种特征&#xff1a; 1、每年获得的飞行里程数 2、玩视频游戏所耗时间百分比 3、…

linux操作系统之线程

1.线程概念 线程是一个轻量级进程,每一个线程都属于一个进程 进程是操作系统资源分配的最小单位,而线程是CPU任务调度的最小单位 线程是一个任务执行的过程,包括创建,调度,消亡 创建:线程空间位于进程空间,进程中的线程,栈区独立,并共享进程中的数据区,文本区,堆区 调度:宏观…

常见的JS混淆及处理办法

1&#xff0c;变量名混淆 文本增添属性的过程中有很多操作空间 原始代码&#xff1a; s[age,job] function xx(){};xx.prototype[s[0]]15 xx.prototype[s[1]]teacheranew xx() 将属性名经过base64加密&#xff0c;并对函数名xx,&#xff0c;数组名s&#xff0c;经过混淆处理…

【C++】C++如何使用结构体中的枚举类型

目录 示例1&#xff1a;在结构体中定义枚举 示例2&#xff1a;使用枚举作为结构体成员的类型 示例3&#xff1a;在结构体方法中使用枚举 注意事项 在C中&#xff0c;可以在结构体&#xff08; struct &#xff09;中定义枚举类型&#xff0c;并使用这些枚举值作为结构体成员…

【网络安全的神秘世界】 文件上传及验证绕过

&#x1f31d;博客主页&#xff1a;泥菩萨 &#x1f496;专栏&#xff1a;Linux探索之旅 | 网络安全的神秘世界 | 专接本 | 每天学会一个渗透测试工具 这个漏洞对于初学者好挖&#xff0c;先找到文件上传的位置 文件上传是web网页中常见的功能之一&#xff0c;通常情况下恶意文…

C# 进制之间的转换(二进制,八进制,十进制,十六进制)

常用的方法是&#xff1a;Convert.ToString(byte value, int toBase)&#xff0c; 并且有多个重载方法&#xff0c; value的类型可以为short&#xff0c;int 等&#xff0c;但必须是整数且不能为负数&#xff0c; 一般默认为十进制 toBase: 返回值的基数&#xff0c;必须是 2、…

以太坊的可扩展性危机:探索执行层的瓶颈

导读&#xff1a;以太坊执行层承担着交易处理、智能合约执行以及保持一致和安全状态的维护等工作。Fuel Labs 撰文解析了以太坊执行层的工作原理&#xff0c;及其在可扩展性方面的发展瓶颈和影响。 Fuel Labs: 执行是指在区块链上执行交易和执行状态更改所需的计算。此计算通常…

【数据结构初阶】一篇文章带你超深度理解【单链表】

hi &#xff01; 目录 前言&#xff1a; 1、链表的概念和结构 2、单链表&#xff08;Single List&#xff0c;简写SList&#xff09;的实现 2.1 定义链表&#xff08;结点&#xff09;的结构 2.2 创建一个链表 2.3 打印链表 2.4 尾插 2.5 头插 2.6 尾删 2.7 头…

python中argparse模块及action=‘store_true‘详解

1. 指定action时 通俗讲&#xff0c;action的作用就是在命令行中指定参数名称时&#xff0c;参数的取值。 如&#xff1a; parser.add_argument(--save-file, actionstore_true, defaultFalse, help是否保存文件) 给参数设置action之后&#xff0c;命令执行时&#xff0c;…

【BUG】已解决:You are using pip version 10.0.1, however version 21.3.1 is available.

You are using pip version 10.0.1, however version 21.3.1 is available. 目录 You are using pip version 10.0.1, however version 21.3.1 is available. 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#…

C基础(学习)2024.7.24

Linux基本命令&#xff0c;vi编译器的使用&#xff0c;简单的编程步骤&#xff0c;程序语言&#xff0c;gcc编译器编译过程&#xff0c;进制转换相关知识可以查看文档http://t.csdnimg.cn/CmqhC 数值表示&#xff0c;词法符号&#xff0c;变量&#xff0c;常量相关知识可以查看…

数据结构初阶(C语言)-二叉树

一&#xff0c;树的概念与结构 树是⼀种非线性的数据结构&#xff0c;它是由 n&#xff08;n>0&#xff09; 个有限结点组成⼀个具有层次关系的集合。把它叫做树是因为它看起来像⼀棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 1.有⼀个特殊的结点&a…

【Linux学习 | 第1篇】Linux介绍+安装

文章目录 Linux1. Linux简介1.1 不同操作系统1.2 Linux系统版本 2. Linux安装2.1 安装方式2.2 网卡设置2.3 安装SSH连接工具2.4 Linux和Windows目录结构对比 Linux 1. Linux简介 1.1 不同操作系统 桌面操作系统 Windows (用户数量最多)MacOS ( 操作体验好&#xff0c;办公人…

昇思25天学习打卡营第22天|基于MindNLP+MusicGen生成自己的个性化音乐

文章目录 昇思MindSpore应用实践1、MusicGen模型简介残差矢量量化&#xff08;RVQ&#xff09;SoundStreamEncodec 2、生成音乐无提示生成文本提示生成音频提示生成 Reference 昇思MindSpore应用实践 本系列文章主要用于记录昇思25天学习打卡营的学习心得。 1、MusicGen模型简…

python使用 tkinter 生成随机颜色

先看效果: 只要不停点击底部的按钮&#xff0c;每次都会生成新的颜色。炫酷啊。 import random import tkinter import tkinter.messagebox from tkinter import Button# todo """ 1. 设置一个按钮&#xff0c;来让用户选择是否显示颜色值 2. 把按钮换成 Label…

谷粒商城实战笔记-错误记录-启动失败

文章目录 一&#xff0c;lombok报错二&#xff0c;Output directory is not specified 一&#xff0c;lombok报错 java: You arent using a compiler supported by lombok, so lombok will not work and has been disabled. Your processor is: com.sun.proxy.$Proxy8 Lombok …

MATLAB的基础知识

matlab的基本小常识 1. 在每行语句后面加上英文分号表示不在命令行窗口显示运行结果。 a 3; a 5 2. 多行注释快捷键&#xff0c;CTRLR。 3. 取消多行注释&#xff0c;CTRLT。 4. 清空工作区的所有变量使用clear。 5. 清空命令行窗口的所有变量使用clc。 6. clc和clear一起使…

初试Ollama本地大模型

准备工作 机器配置&#xff1a; CPUi5-10400内存16GB硬盘SSD 480GB显卡GTX 1660 系统&#xff1a;Ubuntu 18.04 Server NVIDIA驱动安装 - 下载 驱动下载地址&#xff1a;https://www.nvidia.cn/geforce/drivers/ - 获取下载链接 GTX 1660驱动下载链接&#xff1a;https://…

怎么理解FPGA的查找表与CPLD的乘积项

怎么理解 fpga的查找表 与cpld的乘积项 FPGA&#xff08;现场可编程门阵列&#xff09;和CPLD&#xff08;复杂可编程逻辑器件&#xff09;是两种常见的数字逻辑器件&#xff0c;它们在内部架构和工作原理上有着一些显著的区别。理解FPGA的查找表&#xff08;LUT&#xff0c;L…

Git如何将一个分支上的修改转移到另一个分支

在我们使用git进行版本控制时&#xff0c;当代码写错分支&#xff0c;怎么将这些修改转移到正确的分支上去呢&#xff1f;这时&#xff0c;我们可以使用git stath命令来暂存我们的修改&#xff0c;然后再切换到其他分支 未commit&#xff08;提交&#xff09;操作时 1. 先将修…