当前位置: 首页 > news >正文

网络编程代码实例:多进程版

文章目录

  • 前言
  • 代码仓库
  • 内容
  • 代码(有详细注释)
    • server.c
    • client.c
    • Makefile
  • 结果
  • 总结
  • 参考资料
  • 作者的话

前言

网络编程代码实例:多进程版。


代码仓库

  • yezhening/Environment-and-network-programming-examples: 环境和网络编程实例 (github.com)
  • Environment-and-network-programming-examples: 环境和网络编程实例 (gitee.com)

内容

  • 使用传输控制协议(TCP)
  • 一个服务端可连接多个客户端
  • 多次手动通信

代码(有详细注释)

server.c

// 头文件————————————————————
// #include <sys/socket.h> // socket()、sockaddr、bind()、listen()、accept()、recv()、send()
#include <stdio.h>  //(perror())、printf()
#include <stdlib.h> //exit()
// #include <netinet/in.h> //sockaddr_in、(htons())
#include <string.h>    //bzero()、strncpy()
#include <arpa/inet.h> //inet_pton()
// #include <unistd.h>     //close()、fork()
#include <errno.h> //errno// 全局常量————————————————————
const g_serv_port = 6666;     // 服务端的端口号
const g_listen_max_count = 5; // 监听的最大连接数
const g_buff_size = 64;      // 消息缓冲区的大小// 函数声明————————————————————
void handle_request(int connect_fd); // 处理请求// 主函数————————————————————
int main(int arg, char *argv[])
{// 网络连接————————————————————int listen_fd; // 监听套接字文件描述符// 创建套接字并获取套接字文件描述符if ((listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1){perror("socket() error");exit(EXIT_FAILURE);}struct sockaddr_in serv_addr; // 服务端网络信息结构体// 初始化服务端网络信息结构体bzero(&serv_addr, sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(g_serv_port);if ((inet_pton(AF_INET, "0.0.0.0", &serv_addr.sin_addr)) != 1){perror("inet_pton() error");exit(EXIT_FAILURE);}// 绑定套接字与网络信息if ((bind(listen_fd, (struct sockaddr *)(&serv_addr), sizeof(serv_addr))) == -1){if ((close(listen_fd)) == -1){perror("bind() close() error");exit(EXIT_FAILURE);}perror("bind() error");exit(EXIT_FAILURE);}// 套接字设置被动监听状态if ((listen(listen_fd, g_listen_max_count)) == -1){if ((close(listen_fd)) == -1){perror("listen() close() error");exit(EXIT_FAILURE);}perror("listen() error");exit(EXIT_FAILURE);}struct sockaddr_in clie_addr; // 客户端网络信息结构体int clie_addr_size;           // 客户端网络信息结构体大小int connect_fd;               // 连接套接字文件描述符bzero(&clie_addr, sizeof(clie_addr));clie_addr_size = sizeof(struct sockaddr);pid_t pid; // 进程号// 循环监听客户端请求// 原则:父进程不能退出,子进程可以退出while (1){// 与客户端建立连接if ((connect_fd = accept(listen_fd, (struct sockaddr *)(&clie_addr), &clie_addr_size)) == -1){perror("accept() error");continue; // 继续监听}// 创建子进程处理请求pid = fork();if (pid == -1) // 错误{perror("fork() error");continue; // 继续监听}else if (pid == 0) // 子进程{if ((close(listen_fd)) == -1) // 1.关闭监听套接字文件描述符{if ((close(connect_fd)) == -1){perror("fork() close() connect_fd child_process error");exit(EXIT_FAILURE); // 子进程退出}perror("fork() close() listen_fd child_process error");exit(EXIT_FAILURE); // 子进程退出}handle_request(connect_fd); // 2.处理请求if ((close(connect_fd)) == -1) // 3.关闭连接套接字文件描述符{perror("fork() close() connect_fd2 child_process error");exit(EXIT_FAILURE); // 子进程退出}exit(EXIT_SUCCESS);}else if (pid > 0) // 父进程{if ((close(connect_fd)) == -1) // 关闭连接套接字文件描述符{perror("fork() close() connect_fd parent_process error");continue; // 继续监听}}}if ((close(listen_fd)) == -1) // 父进程关闭监听套接字文件描述符。实际不会执行{perror("close() listen_fd error");exit(EXIT_FAILURE);}return 0;
}// 函数定义————————————————————
// 处理请求
void handle_request(int connect_fd) // 参数:连接套接字文件描述符
{// 传输消息————————————————————char msg_recv[g_buff_size]; // 从客户端接收的消息缓冲区char msg_send[g_buff_size]; // 发送到客户端的消息缓冲区int recv_bytes;             // 接收的消息字节数while (1) // 循环接收和发送消息{bzero(&msg_recv, sizeof(*msg_recv));bzero(&msg_send, sizeof(*msg_send));recv_bytes = recv(connect_fd, msg_recv, g_buff_size, 0); // 接收消息if (recv_bytes > 0) // 有消息{printf("Received message: %s", msg_recv); // 接收的消息strncpy(msg_send, msg_recv, g_buff_size);               // 发送的消息if ((send(connect_fd, msg_send, g_buff_size, 0)) == -1) // 发送消息{perror("send() error");return; // 函数返回后,关闭连接套接字文件描述符,结束子进程}}else if (recv_bytes == 0) // 文件末尾EOF:在客户端标准输入Ctrl+D{printf("The process %d received the end of file\n", getpid());return; // 函数返回后,关闭连接套接字文件描述符,结束子进程}else if ((recv_bytes == -1) && (errno == EINTR)) // 信号或网络中断recv(){continue; // 继续接收消息}else if (recv_bytes == -1) // 错误{perror("recv() error");return; // 函数返回后,关闭连接套接字文件描述符,结束子进程}}return;
}

client.c

// 头文件————————————————————
// #include <sys/socket.h> //socket()、sockaddr、connect()、send()、recv()
#include <stdio.h>  //(perror())、printf()、(fgets())
#include <stdlib.h> //exit()
// #include <netinet/in.h> //sockaddr_in、(htons())
#include <string.h>    //bzero()、strncpy()
#include <arpa/inet.h> //inet_pton()
// #include <unistd.h>     //close()
#include <errno.h> //errno// 全局常量————————————————————
const g_serv_port = 6666; // 服务端端口号
const g_buff_size = 64;   // 消息缓冲区大小// 函数声明————————————————————
void handle(int sock_fd); // 处理// 主函数————————————————————
int main(int argc, char *argv[])
{// 网络连接————————————————————int sock_fd; // 套接字文件描述符// 创建套接字并获取套接字文件描述符if ((sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1){perror("socket() error");exit(EXIT_FAILURE);}struct sockaddr_in serv_addr; // 服务端网络信息结构体// 初始化服务端网络信息结构体bzero(&serv_addr, sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(g_serv_port);if ((inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)) != 1){perror("inet_pton() error");exit(EXIT_FAILURE);}// 与服务端建立连接if ((connect(sock_fd, (struct sockaddr *)(&serv_addr), sizeof(serv_addr))) == -1){if ((close(sock_fd)) == -1){perror("connect() close() error");exit(EXIT_FAILURE);}perror("connect() error");exit(EXIT_FAILURE);}handle(sock_fd); // 处理// 关闭套接字文件描述符if ((close(sock_fd)) == -1){perror("close() error");exit(EXIT_FAILURE);}return 0;
}// 函数定义————————————————————
// 处理
void handle(int sock_fd) // 参数:套接字文件描述符
{// 传输消息————————————————————char msg_send[g_buff_size]; // 发送到服务端的消息缓冲区char msg_recv[g_buff_size]; // 从服务端接收的消息缓冲区int recv_bytes;             // 接收的消息字节数while (1) // 循环发送和接收消息{bzero(&msg_send, sizeof(*msg_send));bzero(&msg_recv, sizeof(*msg_recv));printf("Send message: ");if ((fgets(msg_send, g_buff_size, stdin)) == NULL)// 从标准输入获取消息。错误或遇到文件结尾(EOF):在客户端标准输入Ctrl+D,相当于关闭连接{printf("End of connection\n");return; // 函数返回后,关闭套接字文件描述符,结束进程}if ((send(sock_fd, msg_send, g_buff_size, 0)) == -1) // 发送消息{perror("send() error");return; // 函数返回后,关闭连接套接字文件描述符,结束进程}recv_bytes = recv(sock_fd, msg_recv, g_buff_size, 0); // 接收消息if (recv_bytes > 0)                                   // 有数据{printf("Received message: %s", msg_recv); // 接收的消息}else if (recv_bytes == 0) // 服务端进程提前终止,在服务端标准输入Ctrl+C中断进程{printf("Server terminated prematurely\n");return; // 函数返回后,关闭套接字文件描述符,结束进程}else if ((recv_bytes == -1) && (errno == EINTR)) // 信号或网络中断recv(){continue; // 继续发送和接收数据}else if (recv_bytes == -1) // 错误{perror("recv() error");return; // 函数返回后,关闭套接字文件描述符,结束进程}}return;
}

Makefile

#变量
targets = server client#伪目标
.PHONY : all
all : $(targets) #规则
server : server.cgcc -o server server.c client : client.cgcc -o client client.c#伪目标
.PHONY : clean
clean :rm $(targets)

结果

正常情况,服务端表现:

在这里插入图片描述

正常情况,客户端1表现:

在这里插入图片描述

正常情况,客户端2表现:

在这里插入图片描述
正常情况,客户端3表现:

在这里插入图片描述
服务端终止,服务端表现:

在这里插入图片描述

服务端终止,客户端表现:

在这里插入图片描述
客户端终止连接,服务端表现:

在这里插入图片描述
客户端终止连接,客户端表现:

在这里插入图片描述


总结

网络编程代码实例:多进程版。


参考资料

  • 《UNIX环境高级编程(第3版)》作者:W.Richard Stevens,Stephen A.Rago
  • 《UNIX网络编程(第3版)》作者:W.Richard Stevens,Bill Fenner,Andrew M.Rudoff

作者的话

  • 感谢参考资料的作者/博主
  • 作者:夜悊
  • 版权所有,转载请注明出处,谢谢~
  • 如果文章对你有帮助,请点个赞或加个粉丝吧,你的支持就是作者的动力~
  • 文章在描述时有疑惑的地方,请留言,定会一一耐心讨论、解答
  • 文章在认识上有错误的地方, 敬请批评指正
  • 望读者们都能有所收获

相关文章:

网络编程代码实例:多进程版

文章目录 前言代码仓库内容代码&#xff08;有详细注释&#xff09;server.cclient.cMakefile 结果总结参考资料作者的话 前言 网络编程代码实例&#xff1a;多进程版。 代码仓库 yezhening/Environment-and-network-programming-examples: 环境和网络编程实例 (github.com)E…...

一家传统制造企业的上云之旅,怎样成为了数字化转型典范?

众所周知&#xff0c;中国是一个制造业大国。在想要上云以及正在上云的企业当中&#xff0c;传统制造企业也占据了相当大的比例。 那么这类企业在实施数字化转型的时候&#xff0c;应该如何着手&#xff1f;我们不妨来看看一家传统制造企业的现身说法。 国茂股份的数字化转型诉…...

C++入门(C++)

目录 命名空间 1、命名空间的定义 2、命名空间的使用 1、加名空间名称和作用域限定符 2、使用using namespace 命名空间引入 3、使用using将命名空间中某个成员引入 C的输入与输出 缺省参数 1、缺省参数的概念 2、缺省参数分类 1、全缺省参数 2、半缺省参数 函数重载 1、函数重…...

Linux 利用网络同步时间

yum -y install ntp ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime ntpdate ntp1.aliyun.com 创建加入crontab echo "*/20 * * * * /usr/sbin/ntpdate -u ntp.api.bz >/dev/null &" >> /var/spool/cron/rootntp常用服务器 中国国家授…...

炫技亮点 SpringBoot下消灭If Else,让你的代码更亮眼

文章目录 背景案例第一阶段 萌芽第二阶段 屎上雕花第三阶段 策略工厂模式重构第四阶段 优化 总结 背景 大家好&#xff0c;我是大表哥laker。今天&#xff0c;我要和大家分享一篇关于如何使用策略模式和工厂模式消除If Else耦合问题的文章。这个方法能够让你的代码更加优美、简…...

免费ChatGPT接入网站-网站加入CHATGPT自动生成关键词文章排名

网站怎么接入chatGPT 要将ChatGPT集成到您的网站中&#xff0c;需要进行以下步骤&#xff1a; 注册一个OpenAI账户&#xff1a;访问OpenAI网站并创建一个账户。这将提供访问API密钥所需的身份验证凭据。 获取API密钥&#xff1a;在您的OpenAI控制台中&#xff0c;您可以找到您…...

PostgreSQL的数据类型有哪些?

数据类型分类 分类名称说明与其他数据库的对比布尔类型PG支持SQL标准的boolean数据类型与MySQL中的bool、boolean类型相同&#xff0c;占用1字节存储空间数值类型整数类型有2字节的smallint、4字节的int、8字节的bigint&#xff1b;精确类型的小数有numeric&#xff1b;非精确…...

Android 9.0 系统开机自启动第三方app

1.前言 在9.0的系统rom定制化开发中,在framework定制话的功能开发中,在内置的app中,有时候在系统开机以后会要求启动第三方app的功能,所以这就需要在监听开机完成的广播,然后在启动第三方app就可以了,接下来就需要在系统类中监听开机完成的广播流程来实现功能 2.系统开…...

一些想法:关于学习一门新的编程语言

很多人可能长期使用一种编程语言&#xff0c;并感到很有成就感和舒适感&#xff0c;发现学习一种新的编程语言的想法令人生畏而痛苦。或者可能知道并使用多种编程语言&#xff0c;但有一段时间没有学习新的语言。更或者可能只是好奇别人是如何潜心学习新的编程语言并迅速取得成…...

线性代数——矩阵

文章目录 版权声明基础概念矩阵的运算矩阵的加法数与矩阵相乘矩阵的乘法矩阵的转置 矩阵和方程组方阵和行列式伴随矩阵可逆矩阵分块矩阵矩阵的初等变换初等矩阵等价矩阵行阶梯矩阵行最简矩阵初等变换在矩阵求解中的应用 矩阵的秩 版权声明 本文大部分内容皆来自李永乐老师考研…...

taro之小程序持续集成

小程序持续集成 Taro 小程序端构建后支持 CI&#xff08;持续集成&#xff09;的插件 tarojs/plugin-mini-ci。 目前已支持&#xff08;企业&#xff09;微信、京东、字节、支付宝、钉钉、百度小程序 功能包括&#xff1a; 构建完毕后自动唤起小程序开发者工具并打开项目上传…...

Ceph入门到精通-Ceph 编排器简介

第 1 章 Ceph 编排器简介 作为存储管理员&#xff0c;您可以将 Ceph 编排器与 Cephadm 实用程序搭配使用&#xff0c;能够发现设备并在 Red Hat Ceph Storage 集群中创建服务。 1.1. 使用 Ceph Orchestrator Red Hat Ceph Storage Orchestrators 是经理模块&#xff0c;主要…...

【Feign扩展】OpenFeign日志打印Http请求参数和响应数据

SpringBoot使用log4j2 在Spring Boot中所有的starter 都是基于spring-boot-starter-logging的&#xff0c;默认使用Logback。使用Log4j2的话&#xff0c;你需要排除 spring-boot-starter-logging 的依赖&#xff0c;并添加 spring-boot-starter-log4j2的依赖。 配置依赖 <…...

MongoDB (零) 安装和简单使用

1.安装(Ubuntu) 1.1.安装gnupg sudo apt-get install gnupg1.2.获取GPG Key curl -fsSL https://pgp.mongodb.com/server-6.0.asc | \sudo gpg -o /usr/share/keyrings/mongodb-server-6.0.gpg \--dearmor1.3.创建本地文件 echo "deb [ archamd64,arm64 signed-by/usr…...

Java中的异常是什么?

Java中的异常是指在程序运行时发生的错误或异常情况。这些异常可能会导致程序崩溃或无法正确执行&#xff0c;因此需要在代码中进行处理。Java中的异常机制可以帮助程序员捕获并处理异常&#xff0c;从而保证程序的稳定性和可靠性。 Java中的异常分为两种类型&#xff1a;受检…...

微短剧“小阳春”,“爱优腾芒”抢滩登陆?

降本增效一整年&#xff0c;长视频平台们似乎扭转了市场对于它们“烧钱”的印象。 爱奇艺宣布2022全年盈利&#xff0c;腾讯视频宣布从去年10月起开始盈利&#xff0c;视频平台们结束了一场“无限战争”。 与此同时&#xff0c;随着短视频平台的崛起&#xff0c;视频内容的形…...

C++菱形继承(再剖析)

当子类对象给父类对象的时候&#xff0c;怎么找公共的虚基类&#xff08;A&#xff09; 就得通过偏移量来算虚基类的位置 ---------------------------------------------------------------------------------------------------------------------------- 我们来分析一下B…...

java获取星期几

如果你要问 java什么时候学习比较好&#xff0c;那么答案肯定是 java的星期几。 在 Java中&#xff0c;你可以使用 public static void main &#xff08;&#xff09;方法来获取一个类的所有成员变量&#xff0c;然后在所有类中调用这个方法来获取对象的所有成员变量。它能以对…...

【TypeScript】03-TypeScript基本类型

TypeScript基本类型 在TypeScript中&#xff0c;基本类型是非常重要的一部分&#xff0c;下面我们将详细介绍TypeScript中的基本类型。 基本类型约束 在TypeScript中&#xff0c;可以使用基本类型来约束变量的类型。常见的基本类型有&#xff1a; number&#xff1a;表示数…...

什么是跨域?

什么是跨域 什么是跨域&#xff1f; 什么是同源策略及其限制内容&#xff1f; 同源策略是一种约定&#xff0c;它是浏览器最核心也最基本的安全功能&#xff0c;如果缺少了同源策略&#xff0c;浏览器很容易受到XSS、CSRF等攻击。所谓同源是指"协议域名端口"三者相…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

Mac下Android Studio扫描根目录卡死问题记录

环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中&#xff0c;提示一个依赖外部头文件的cpp源文件需要同步&#xff0c;点…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习

禁止商业或二改转载&#xff0c;仅供自学使用&#xff0c;侵权必究&#xff0c;如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

动态 Web 开发技术入门篇

一、HTTP 协议核心 1.1 HTTP 基础 协议全称 &#xff1a;HyperText Transfer Protocol&#xff08;超文本传输协议&#xff09; 默认端口 &#xff1a;HTTP 使用 80 端口&#xff0c;HTTPS 使用 443 端口。 请求方法 &#xff1a; GET &#xff1a;用于获取资源&#xff0c;…...

五子棋测试用例

一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏&#xff0c;有着深厚的文化底蕴。通过将五子棋制作成网页游戏&#xff0c;可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家&#xff0c;都可以通过网页五子棋感受到东方棋类…...

二维FDTD算法仿真

二维FDTD算法仿真&#xff0c;并带完全匹配层&#xff0c;输入波形为高斯波、平面波 FDTD_二维/FDTD.zip , 6075 FDTD_二维/FDTD_31.m , 1029 FDTD_二维/FDTD_32.m , 2806 FDTD_二维/FDTD_33.m , 3782 FDTD_二维/FDTD_34.m , 4182 FDTD_二维/FDTD_35.m , 4793...

大数据治理的常见方式

大数据治理的常见方式 大数据治理是确保数据质量、安全性和可用性的系统性方法&#xff0c;以下是几种常见的治理方式&#xff1a; 1. 数据质量管理 核心方法&#xff1a; 数据校验&#xff1a;建立数据校验规则&#xff08;格式、范围、一致性等&#xff09;数据清洗&…...