当前位置: 首页 > 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等攻击。所谓同源是指"协议域名端口"三者相…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

测试微信模版消息推送

进入“开发接口管理”--“公众平台测试账号”&#xff0c;无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息&#xff1a; 关注测试号&#xff1a;扫二维码关注测试号。 发送模版消息&#xff1a; import requests da…...

汇编常见指令

汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX&#xff08;不访问内存&#xff09;XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...

Golang——7、包与接口详解

包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...

在 Spring Boot 中使用 JSP

jsp&#xff1f; 好多年没用了。重新整一下 还费了点时间&#xff0c;记录一下。 项目结构&#xff1a; pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...

Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?

Pod IP 的本质与特性 Pod IP 的定位 纯端点地址&#xff1a;Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址&#xff08;如 10.244.1.2&#xff09;无特殊名称&#xff1a;在 Kubernetes 中&#xff0c;它通常被称为 “Pod IP” 或 “容器 IP”生命周期&#xff1a;与 Pod …...

通过MicroSip配置自己的freeswitch服务器进行调试记录

之前用docker安装的freeswitch的&#xff0c;启动是正常的&#xff0c; 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...

鸿蒙(HarmonyOS5)实现跳一跳小游戏

下面我将介绍如何使用鸿蒙的ArkUI框架&#xff0c;实现一个简单的跳一跳小游戏。 1. 项目结构 src/main/ets/ ├── MainAbility │ ├── pages │ │ ├── Index.ets // 主页面 │ │ └── GamePage.ets // 游戏页面 │ └── model │ …...

阿里云Ubuntu 22.04 64位搭建Flask流程(亲测)

cd /home 进入home盘 安装虚拟环境&#xff1a; 1、安装virtualenv pip install virtualenv 2.创建新的虚拟环境&#xff1a; virtualenv myenv 3、激活虚拟环境&#xff08;激活环境可以在当前环境下安装包&#xff09; source myenv/bin/activate 此时&#xff0c;终端…...