网络编程:服务器模型-并发服务器-多进程

并发服务器概念:

并发服务器同一时刻可以处理多个客户机的请求

设计思路:

并发服务器是在循环服务器基础上优化过来的

(1)每连接一个客户机,服务器立马创建子进程或者子线程来跟新的客户机通信 (accept之后的),服务器不会与客户端进行通信!!!

(2)IO多路复用技术

1、多进程实现并发服务器

思想:

主进程专门用于连接多个客户端的请求,若有一路客户端连接进来,主进程就创建一个子进程,用该子进程来处理该客户端的业务数据。

回顾:创建进程

 #include <sys/types.h>

 #include <unistd.h>

    pid_t fork(void);
    功能:创建一个子进程
    参数:无
    返回值:pid_t就是int类型的别名
        返回值大于0,代表此时是父进程,该值的含义为创建成功的子进程的ID号
        返回值等于0,代表此时是子进程
        返回值小于0,创建失败可以perror

源代码:

tcp_server.c 

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>//sockaddr_in
#include <unistd.h>
#include <arpa/inet.h>   // 包含 inet_addr 函数的声明 
#include <sys/select.h>
#include <sys/time.h>
#define BUF_SIZE 20int main(int argc, const char *argv[])
{//1.socketint iServer = socket(AF_INET, SOCK_STREAM, 0);if(-1 == iServer){puts("----------1、create socket error!");return -1;}printf("----------1、create socket ok! iServer:%d", iServer);//0,1,2标准输入输出出错,iServer为3//2.bindstruct sockaddr_in stServer;stServer.sin_family = AF_INET;//第一个成员stServer.sin_port = htons(8888);//第二个成员stServer.sin_addr.s_addr = inet_addr("127.0.0.1");//将点分十进制ip地址转换为32位无符号整数int ret = bind(iServer, (struct sockaddr *)&stServer, sizeof(struct sockaddr));if(-1 == ret){puts("----------2、bind error!");return -1;}puts("----------2、bind ok!");//3.listenret = listen(iServer, 5);if(-1 == ret){puts("----------3、listen error!");return -1;}puts("----------3、listen ok!");//4.acceptstruct sockaddr_in stClient;//存放对方的主机信息socklen_t len = sizeof(struct sockaddr_in);char buf[BUF_SIZE] = {0};fd_set stFdr;//文件描述符集合表,大小1024FD_ZERO(&stFdr);//将文件描述符集合表中所有内容清零while(1){FD_SET(iServer, &stFdr);FD_SET(0, &stFdr);//selectret = select(iServer + 1, &stFdr, NULL, NULL, NULL);if(ret <= 0){continue;}printf("select ok, ret = %d\r\n", ret);//FD_ISSETif(FD_ISSET(0, &stFdr)){memset(buf, 0, BUF_SIZE);fgets(buf, BUF_SIZE, stdin);printf("fgets ok, data = %s\r\n", buf);}if(FD_ISSET(iServer, &stFdr)){int iClient = accept(iServer, (struct sockaddr *)&stClient, &len);if(-1 == iClient){continue;//当前客户端出错转向下一个客户端	}printf("----------4、accept ok! iClient = %d\r\n",iClient );//标准输入输出出错,所以下一个打开的文件一定是3//5.recv/sendret = recv(iClient, buf, BUF_SIZE, 0);if(ret <= 0){close(iClient);continue;}printf("----------recv data ok! buf = %s\r\n",buf);//sendret = send(iClient, buf, BUF_SIZE, 0);if(ret <= 0){close(iClient);continue;}printf("----------send data ok! %s\r\n",buf);//close(iClient);//断开当前客户端}}return 0;
}

tcp_client.c

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>#define BUF_SIZE 20
//main函数参数,如果需要键入IP则给定即可
int main(int argc, const char *argv[])
{//1、socketint iClient = 	socket(AF_INET, SOCK_STREAM, 0);if(-1 == iClient){puts("----------1、create socket error!");return -1;}puts("----------1、create socket ok!");//2、connectstruct sockaddr_in stServer;stServer.sin_family = AF_INET;stServer.sin_port = htons(8888);//stServer.sin_addr.s_addr = inet_addr("192.168.15.71");stServer.sin_addr.s_addr = inet_addr("127.0.0.1");int ret = connect(iClient, (struct sockaddr *)&stServer, sizeof(struct sockaddr_in));if(-1 == ret){puts("----------2、connect error!");return -1;}puts("----------2、connect ok!");char buf[BUF_SIZE] = {0};while(1){//gets();//char *fgets(char *s, int size, FILE *stream);fgets(buf, BUF_SIZE, stdin);//更安全,边界检查//3、send recvret = send(iClient, buf, BUF_SIZE, 0);if(-1 == ret){puts("----------3、send data error!");}printf("----------3、send data ok! buf = %s\r\n",buf);//recv//函数原型:ssize_t recv(int sockfd, void *buf, size_t len, int flags);memset(buf, 0, BUF_SIZE);ret = recv(iClient, buf, BUF_SIZE, 0);if(-1 == ret){puts("----------4、recv error!");return -1;}printf("----------4、recv data ok! buf = %s\r\n",buf);}close(iClient);return 0;
}

思考:

多进程并发服务器的缺点:每连接一个客户端,就为其创建子进程,客户端数量比较大时,服务器的运 行效率就会变低。

注:

以上代码只能实现:

        ①客户端连接到服务器端,只能发送一条数据,之后发送不成功

        ②服务器端可以检测标准输入给自己

测试结果如下图:

2、多进程实现并发服务器-优化版本

tcp_server.c 

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>//sockaddr_in
#include <unistd.h>
#include <arpa/inet.h>   // 包含 inet_addr 函数的声明 
#include <sys/select.h>
#include <sys/time.h>
#define BUF_SIZE 20int main(int argc, const char *argv[])
{//1.socketint iServer = socket(AF_INET, SOCK_STREAM, 0);if(-1 == iServer){puts("----------1、create socket error!");return -1;}printf("----------1、create socket ok! iServer:%d", iServer);//0,1,2标准输入输出出错,iServer为3//2.bindstruct sockaddr_in stServer;stServer.sin_family = AF_INET;//第一个成员stServer.sin_port = htons(9999);//第二个成员stServer.sin_addr.s_addr = inet_addr("127.0.0.1");//将点分十进制ip地址转换为32位无符号整数int ret = bind(iServer, (struct sockaddr *)&stServer, sizeof(struct sockaddr));if(-1 == ret){puts("----------2、bind error!");return -1;}puts("----------2、bind ok!");//3.listenret = listen(iServer, 5);if(-1 == ret){puts("----------3、listen error!");return -1;}puts("----------3、listen ok!");//4.acceptstruct sockaddr_in stClient;//存放对方的主机信息socklen_t len = sizeof(struct sockaddr_in);char buf[BUF_SIZE] = {0};fd_set stFdr;//文件描述符集合表,大小1024FD_ZERO(&stFdr);//将文件描述符集合表中所有内容清零FD_SET(iServer, &stFdr);//iServer添加到原文件描述符集合表中int max = iServer;while(1){//selectfd_set stFdrTmp = stFdr;	//定义临时文件描述符集合表ret = select(max + 1, &stFdrTmp, NULL, NULL, NULL);if(ret <= 0){printf("select error!\r\n");continue;}printf("select ok, ret = %d\r\n", ret);int i = 0;for(i = 0; i < max + 1; i++){if(FD_ISSET(i, &stFdrTmp)){	 // 循环判断哪个文件描述符被置位//操作if(i == iServer){ // i == 3, 操作int iClient = accept(iServer, (struct sockaddr *)&stClient, &len);if(-1 == iClient){continue;//当前客户端出错转向下一个客户端	}printf("----------4、accept ok! iClient = %d\r\n",iClient );//标准输入输出出错,所以下一个打开的文件一定是4FD_SET(iClient, &stFdr);//更新maxif(max < iClient){max = iClient;}}else{ // 与多个客户端保持连接//recv/sendret = recv(i, buf, BUF_SIZE, 0);if(ret > 0){printf("recv:%s\r\n", buf);send(i, buf, BUF_SIZE, 0);}else{close(i);FD_CLR(i, &stFdr);}}}}}return 0;
}

tcp_client.c

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>#define BUF_SIZE 20
//main函数参数,如果需要键入IP则给定即可
int main(int argc, const char *argv[])
{//1、socketint iClient = 	socket(AF_INET, SOCK_STREAM, 0);if(-1 == iClient){puts("----------1、create socket error!");return -1;}puts("----------1、create socket ok!");//2、connectstruct sockaddr_in stServer;stServer.sin_family = AF_INET;stServer.sin_port = htons(9999);//stServer.sin_addr.s_addr = inet_addr("192.168.15.71");//stServer.sin_addr.s_addr = inet_addr("192.168.15.71");stServer.sin_addr.s_addr = inet_addr("127.0.0.1");int ret = connect(iClient, (struct sockaddr *)&stServer, sizeof(struct sockaddr_in));if(-1 == ret){puts("----------2、connect error!");return -1;}puts("----------2、connect ok!");char buf[BUF_SIZE] = {0};while(1){//gets();//char *fgets(char *s, int size, FILE *stream);fgets(buf, BUF_SIZE, stdin);//更安全,边界检查//3、send recvret = send(iClient, buf, BUF_SIZE, 0);if(-1 == ret){puts("----------3、send data error!");}printf("----------3、send data ok! buf = %s\r\n",buf);//recv//函数原型:ssize_t recv(int sockfd, void *buf, size_t len, int flags);memset(buf, 0, BUF_SIZE);ret = recv(iClient, buf, BUF_SIZE, 0);if(-1 == ret){puts("----------4、recv error!");return -1;}printf("----------4、recv data ok! buf = %s\r\n",buf);}close(iClient);return 0;
}

注:

以上代码可以实现:

        ①多个客户端与服务器连接 并 发送&回显数据

测试结果如下图:

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

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

相关文章

QT--4

QT 使用定时器完成闹钟 #include "widget.h" #include "ui_widget.h"void Widget::timestart() {timer.start(1000); }void Widget::timeend() {timer.stop(); }Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(t…

分类预测 | Matlab实现DBO-CNN-SVM蜣螂算法优化卷积神经网络结合支持向量机多特征分类预测

分类预测 | Matlab实现DBO-CNN-SVM蜣螂算法优化卷积神经网络结合支持向量机多特征分类预测 目录 分类预测 | Matlab实现DBO-CNN-SVM蜣螂算法优化卷积神经网络结合支持向量机多特征分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现DBO-CNN-SVM蜣螂算法…

【卫星影像三维重建-全流程代码实现】点云Mesh重构

点云—>Mesh模型 1.介绍1.1 背景1.2 效果示意 2 算法实现2.1 依赖库2.2 实验数据2.3 代码实现2.4 实验效果 3.总结 1.介绍 1.1 背景 &#xff08;1&#xff09;本文主要内容是将三维点云&#xff08;离散的三维点&#xff09;进行表面重建生成Mesh网格&#xff0c;之前有篇…

Middle for Mac:简洁高效的文本编辑软件

追求简洁与高效&#xff1f;Middle for Mac将是您文本编辑的最佳选择。这款Mac平台上的文本编辑器&#xff0c;以其独特的魅力和实用的功能&#xff0c;赢得了众多用户的喜爱。 Middle注重用户体验&#xff0c;采用简洁直观的界面设计&#xff0c;让您能够迅速上手并享受高效的…

巩固学习6

正则表达式 又称规则表达式&#xff0c;Regular Expression&#xff0c;在代码中常简写为regex、regexp或RE&#xff09;&#xff0c;是一种文本模式&#xff0c;包括普通字符&#xff08;例如&#xff0c;a到z之间的字母&#xff09;和特殊字符&#xff08;称为“元字符”&…

今天开发了一款软件,我竟然只用敲了一个字母(文末揭晓)

软件课题&#xff1a;Python实现打印100内数学试题软件及开发过程 一、需求管理&#xff1a; 1.实现语言&#xff1a;Python 2.打印纸张&#xff1a;A4 3.铺满整张纸 4.打包成exe 先看效果&#xff1a; 1. 2.电脑打印预览 3.打印到A4纸效果&#xff08;晚上拍的&#x…

【实践】使用vscode来debug go程序的尝鲜

配置 首先&#xff0c;当然得配置好vscode 的go环境&#xff0c; 装个go插件就基本满足了 配置 launch.json, 可以配置多个环境的程序启动参数&#xff08;很友好&#xff09; {"version": "0.2.0","configurations": [{"name": &…

享元模式详解

享元模式 1 概述 定义&#xff1a; ​ 运用共享技术来有效地支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似对象的开销&#xff0c;从而提高系统资源的利用率。 2 结构 享元&#xff08;Flyweight &#xff09;模式中存…

linux学习:视频输入+V4L2

目录 V4L2 视频采集流程 代码例子 核心命令字和结构体 VIDIOC_ENUM_FMT VIDIOC_G_FMT / VIDIOC_S_FMT / VIDIOC_TRY_FM VIDIOC_REQBUFS VIDIOC_QUERYBUF VIDIOC_QBUF /VIDIOC_DQBUF VIDIOC_STREAMON / VIDIOC_STREAMOFF V4L2 是 Linux 处理视频的最新标准代码模块&…

力扣HOT100 - 45. 跳跃游戏 II

解题思路&#xff1a; 贪心 class Solution {public int jump(int[] nums) {int end 0;int maxPosition 0;int steps 0;for (int i 0; i < nums.length - 1; i) {maxPosition Math.max(maxPosition, i nums[i]);if (i end) {end maxPosition;steps;}}return steps;…

Java | Leetcode Java题解之第86题分隔链表

题目&#xff1a; 题解&#xff1a; class Solution {public ListNode partition(ListNode head, int x) {ListNode small new ListNode(0);ListNode smallHead small;ListNode large new ListNode(0);ListNode largeHead large;while (head ! null) {if (head.val < x…

java sql中 大于 小于 大于等于 小于等于 代替符号

在写java时sql会经常会忘记大于小于号的表示方法导致无法运行&#xff0c;总结一下 第一种方法&#xff1a; < &#xff1a;< < &#xff1a; < &#xff1a;> &#xff1a; > sql如下&#xff1a; create_at > #{startTime} and create_at < #{end…

Linux系统编程:进程控制

1.进程创建 1.1 fork函数 fork&#xff08;&#xff09;通过复制调用进程来创建一个新进程。新进程称为子进程&#xff0c;是调用进程的精确副本 进程&#xff0c;但以下几点除外&#xff1a; 子进程有自己的PID&#xff0c;此PID与任何现有进程组的ID不匹配子进程的父进程ID…

【全开源】废品回收微信小程序基于FastAdmin+ThinkPHP+UniApp

介绍 一款基于FastAdminThinkPHPUniApp开发的废品回收系统&#xff0c;适用废品回收站、再生资源回收公司上门回收使用的小程序 功能特性 1、会员注册 支持小程序授权注册和手机号注册 2、回收品类 可设置回收品类&#xff0c;废纸、废金属、废玻璃、旧衣服等 3、今日指导价…

简单实现---基于STL的演讲比赛流程管理系统(C++实现)

前言 事先声明&#xff1a;本文章中编写的代码仅用于学习算法思想和编写基础形式使用&#xff0c;并未进行太多的代码优化&#xff0c;因此&#xff0c;若需要对代码进行优化以及异常处理的小伙伴们&#xff0c;可自行添加相关操作&#xff0c;谢谢&#xff01; 一、题…

jenkins使用gitLab(极狐)认证登陆

jenkins安装 GitLab Authentication插件 我因为java版本和最新GitLab Authentication 1.19版本不兼容&#xff0c;选择了本地安装 找个历史版本1.13版本&#xff0c;然后下载到电脑上 - 本地上传插件并安装 在极狐上创建一个应用 - 配置应用信息 应用名&#xff1a;jenkinsLo…

[Linux][网络][高级IO][一][五种IO模型][同步通信][异步通信][非阻塞IO]详细讲解

目录 0.预备知识 && 思考问题1.五种IO模型0.形象理解五种模型1.阻塞IO2.非阻塞IO3.信号驱动IO4.多路转接/多路复用5.异步IO 2.高级IO重要概念1.同步通信 vs 异步通信2.阻塞 vs 非阻塞 3.非阻塞IO1.fcntl()2.实现SetNonBlock 0.预备知识 && 思考问题 网络通信本…

了解 GaussDB SQL 中 CASE 表达式

一、前言 SQL 是用于访问和处理数据库的标准计算机语言。GaussDB 支持 SQL 标准&#xff08;默认支持 SQL2、SQL3 和 SQL4 的主要特性&#xff09;。 本系列将以《云数据库 GaussDB—SQL 参考》在线文档为主线进行介绍。 二、CASE Expression&#xff08;CASE 表达式&#x…

sCrypt受邀在中国人民大学举办《区块链与数字经济》课程讲座

4月17日&#xff0c;可一科技特邀美国sCrypt公司的开发工程师周全&#xff0c;在中国人民大学的《区块链与数字经济》课程上进行了讲座。周全讲解了区块链的分布式设计、不可篡改特性&#xff0c;以及智能合约的基本原理&#xff0c;利用“智能家居触发机制”等生动比喻&#x…

laravel 使用 MongoDB

MongoDB MongoDB是一个基于分布式文件存储的数据库。由C语言编写。MongoDB 提供了面向文档的存储方式&#xff0c;操作起来比较简单和容易&#xff0c;支持“无模式”的数据建模&#xff0c;可以存储比较复杂的数据类型&#xff0c;是一款非常流行的文档类型数据库 使用场景 …