Linux网络编程---多进/线程并发服务器

news2024/11/25 17:03:12

一、多进程并发服务器

实现一个服务器可以连接多个客户端,每当accept函数等待到客户端进行连接时 就创建一个子进程

思路分析:

核心思路:让accept循环阻塞等待客户端,每当有客户端连接时就fork子进程,让子进程去和客户端进行通信,父进程用于监听并使用信号捕捉回收子进程(子进程关闭用于监听的套接字lfd,父进程关闭用于通信的cfd) 

服务端server.c代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<arpa/inet.h>
#include<ctype.h>
#include<sys/socket.h>
#include<unistd.h>
#include<string.h>
#include<strings.h>
#include<errno.h>
#include<pthread.h>
#include<signal.h>
#include<sys/wait.h>

#define SERV_PORT 9527

void sys_err(const char *str)
{
        perror(str);
        exit(1);
}

void catch_child(int signum)
{
        while(waitpid(0,NULL,WNOHANG) > 0);
        return ;
}

int main(int argc,char *argv[])
{
        int lfd = 0,cfd = 0;
        pid_t pid;
        int ret;
        char buf[BUFSIZ],client_IP[1024];//4096

        struct sockaddr_in serv_addr,clit_addr;
        socklen_t clit_addr_len;

        bzero(&serv_addr,sizeof(serv_addr));//将地址结构清零
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(SERV_PORT);
        serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

        lfd = socket(AF_INET,SOCK_STREAM,0);
        if (lfd == -1)
        {
                sys_err("socket errno");
        }

        bind(lfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));

        listen(lfd,128);

        clit_addr_len = sizeof(clit_addr);

        while(1)
        {
                cfd = accept(lfd,(struct sockaddr *)&clit_addr,&clit_addr_len);
                if (cfd == -1)
                {
                        sys_err("accept error");         
                }
                printf("client ip is:%s port:%d\n",inet_ntop(AF_INET,&clit_addr.sin_addr.s_addr,client_IP,sizeof(client_IP)),ntohs(clit_addr.sin_port));

                pid = fork();
                if (pid < 0)
                {
                        sys_err("fork error");
                }
                else if (pid == 0)
                {
                        close(lfd);
                        break;
                }
                else
                {
                        struct sigaction act;

                        act.sa_handler = catch_child;
                        sigemptyset(&(act.sa_mask));
                        act.sa_flags = 0;

                        ret = sigaction(SIGCHLD,&act,NULL);
                        if (ret != 0)
                        {
                                sys_err("sigaction error");
                        }
                        close(cfd);
                        continue;
                }
        }

        if (pid == 0)
        {
                for(;;)
                {
                        ret = read(cfd,buf,sizeof(buf));
                        if (ret == 0)
                        {
                                close(cfd);
                                exit(1);
                        }

                        for (int i = 0;i<ret;i++)
                        {
                                buf[i] = toupper(buf[i]);
                        }

                        write(cfd,buf,ret);
                        write(STDOUT_FILENO,buf,ret);
                }
        }
        
        return 0;
}

一个服务端三个客户端执行多进程服务器并发输出如下: 

补充:

二、多线程并发服务器: 

思路分析:

核心思路:设置监听循环由主线程阻塞等待客户端连接,每当接受到新的客户端连接时,主线程会创建一个新的子线程来处理与该客户端的通信,而主线程继续执行监听循环等待其他客户端(主线程专注于接受新连接,子线程专注于处理客户端请求)

 服务端server.c代码如下:

#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>

#include "wrap.h"

#define MAXLINE 8192
#define SERV_PORT 8000

struct s_info {       //定义一个结构体, 将地址结构跟cfd捆绑
    struct sockaddr_in cliaddr;
    int connfd;
};

void *do_work(void *arg)
{
    int n,i;
    struct s_info *ts = (struct s_info*)arg;
    char buf[MAXLINE];
    char str[INET_ADDRSTRLEN];      //#define INET_ADDRSTRLEN 16  可用"[+d"查看

    while (1) {
        n = Read(ts->connfd, buf, MAXLINE);  //读客户端
        if (n == 0) {
            printf("the client %d closed...\n", ts->connfd);
            break;                           //跳出循环,关闭cfd
        }
        printf("received from %s at PORT %d\n",
                inet_ntop(AF_INET, &(*ts).cliaddr.sin_addr, str, sizeof(str)),
                ntohs((*ts).cliaddr.sin_port));  //打印客户端信息(IP/PORT)

        for (i = 0; i < n; i++) 
            buf[i] = toupper(buf[i]);            //小写-->大写

        Write(STDOUT_FILENO, buf, n);           //写出至屏幕
        Write(ts->connfd, buf, n);              //回写给客户端
    }
    Close(ts->connfd);

    return (void *)0;            //pthread_exit(0);
}

int main(void)
{
    struct sockaddr_in servaddr, cliaddr;
    socklen_t cliaddr_len;
    int listenfd, connfd;
    pthread_t tid;

    struct s_info ts[256];      //创建结构体数组.
    int i = 0;

    listenfd = Socket(AF_INET, SOCK_STREAM, 0);        //创建一个socket, 得到lfd

    bzero(&servaddr, sizeof(servaddr));               //地址结构清零
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);     //指定本地任意IP
    servaddr.sin_port = htons(SERV_PORT);             //指定端口号 

    Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));   //绑定

    Listen(listenfd, 128);             //设置同一时刻链接服务器上限数

    printf("Accepting client connect ...\n");

    while (1) {
        cliaddr_len = sizeof(cliaddr);
        connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len); //阻塞监听客户端链接请求
        ts[i].cliaddr = cliaddr;    //把文件描述符和客户端地地址结构组织到一个结构体变量中
        ts[i].connfd = connfd;

        pthread_create(&tid, NULL, do_work, (void*)&ts[i]);//表结构体变量作为参数传递到子线程
        pthread_detach(tid);                //子线程分离,防止僵线程产生.
        i++;
    }

    return 0;
}

执行输出如下: 

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

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

相关文章

【调研分析】机器视觉及其系统

机器视觉 定义 机器视觉主要利用计算机模拟人的视觉功能&#xff0c;但不仅限于人眼的简单延伸&#xff0c;而是具备人脑的部分功能&#xff0c;即从客观事物的图像中提取信息、进行处理并加以理解&#xff0c;从而应用于实际的检测识别、测量和控制过程。 机器视觉系统组成 …

JavaEE >> Spring Boot(2)

Spring Boot 配置文件 前面的文章已经介绍了 Spring Boot 项目的创建&#xff0c;上文&#xff0c;本文介绍 Spring Boot 的简单进阶使用。 配置文件的作用 项目中的所有重要数据都是在配置文件中配置的&#xff0c;例如&#xff1a; 数据库的连接信息&#xff08;包括数据…

BossCMS RCE(下)

未授权漏洞 在登录后台的时候通过查看添加用户功能&#xff0c;看能不能挖掘sql注入漏洞&#xff0c;结果发现了个大问题&#xff0c;一个比较好玩的权限逻辑问题。这里添加用户的路由 我们跟进到manager.class.php里面的add()方法&#xff0c;这里先into::basc_class(admin)&…

DS进阶:并查集

一、并查集的原理 在一些应用问题中&#xff0c;需要将n个不同的元素划分成一些不相交的集合。开始时&#xff0c;每个元素自成一个单元素集合&#xff0c;然后按一定的规律将归于同一组元素的集合合并。在此过程中要反复用到查询某一个元素归属于那个集合的运算。适合于描述这…

局部多项式近似与 AMPM 算法

kappa3; %已在您的代码中定义% 定义窗口大小 windowSize (2*kappa1);% 初始化梯度估计值 [rows, cols] size(wrappedPhase); phi_y zeros(rows, cols); phi_x zeros(rows, cols);% 遍历每个窗口 for m 1kappa:rows-kappafor n 1kappa:cols-kappa% 提取局部窗口Z_mn wrap…

python 使用flask_httpauth和pyjwt实现登录权限控制

最近需要用到&#xff0c;学习了一下记录 首先安装依赖 pip install Flask-HTTPAuth pyjwt passlib Welcome to Flask-HTTPAuth’s documentation! — Flask-HTTPAuth documentation Welcome to PyJWT — PyJWT 2.8.0 documentation Passlib 1.7.4 documentation — Passl…

【代码随想录刷题记录】LeetCode27移除元素

题目地址 1. 思路 1.1 基本思路及代码的初步实现 基本思路大体上和卡尔老师的想法是一致的&#xff0c;详见代码随想录&#xff1a;数组&#xff1a;移除元素&#xff0c;暴力法大家都能想到&#xff0c;我这里写一下算法时间复杂度为 O ( n ) O(n) O(n)时候的思路&#xff…

短视频矩阵营销系统 poihuoqu 任意文件读取漏洞复现

0x01 产品简介 短视频矩阵营销系统是由北京华益云数据科技有限公司开发的一款产品,这家公司专注于抖音短视频矩阵营销系统的研发,致力于为企业提供全方位的短视频营销解决方案。华益云抖销短视频矩阵系统可以帮助企业快速搭建多个短视频账号,实现内容的批量制作和发布,提高…

ShardingSphere 5.x 系列【25】 数据分片原理之 SQL 解析

有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot 版本 3.1.0 本系列ShardingSphere 版本 5.4.0 源码地址:https://gitee.com/pearl-organization/study-sharding-sphere-demo 文章目录 1. 分片执行流程1.1 Simple Push Down1.2 SQL Federation2. SQL 解析2.1 解析…

SystemUI KeyButtonView setDarkIntensity 解析

继承自 ImageView KeyButtonDrawable intensity为0时按键颜色为白色。 intensity为1时黑色为的调用堆栈&#xff1a; java.lang.NullPointerException: Attempt to invoke virtual method int java.lang.String.length() on a null object referenceat com.android.systemui.…

嵌入式学习Day18

一、输入两个数&#xff0c;实现排序 代码&#xff1a; #!/bin/bashread -p "please enter n m:" n m if [ $n -gt $m ] thentemp$nn$mm$temp fi echo $n $m运行结果 二、输入一个数判断是否水仙花数 代码&#xff1a; echo narcissistic number read -p "p…

店匠科技技术产品闪耀,引领新质生产力发展

在科技飞速发展的今天,新质生产力正成为推动社会进步和经济高质量发展的核心力量。店匠科技,作为一家致力于为全球B2C电商提供产品和技术解决方案的领先企业,其技术产品不仅体现了新质生产力的创新特质,更在推动电商行业转型升级中发挥了重要作用。 新质生产力,以创新为主导,摆…

Java设计模式 _创建型模式_原型模式(Cloneable)

一、原型模式 1、原型模式&#xff08;Prototype Pattern&#xff09;是用于创建重复的对象&#xff0c;同时又能保证性能比较好。一般对付出较大代价获取到的实体对象进行克隆操作&#xff0c;可以提升性能。 2、实现思路&#xff1a; &#xff08;1&#xff09;、需要克隆的…

macOS 一些系统图标的存放位置 icns

macOS 一些系统图标的存放位置 icns macOS 中有很多好看的图标&#xff0c;有时候就想用一下它&#xff0c;我来告诉你他们的具体位置。 系统图标位置&#xff0c;像各种通用文件类型的图标都在这里面&#xff0c;里面好多高清的系统图标 /System/Library/CoreServices/Core…

济宁市中考报名照片要求及手机拍照采集证件照方法

随着中考报名季的到来&#xff0c;并且进入了中考报名演练阶段&#xff0c;济宁市的广大考生和家长都开始忙碌起来。报名过程中&#xff0c;上传一张符合要求的证件照是必不可少的环节。本文将详细介绍济宁市中考报名照片的具体要求&#xff0c;并提供一些实用的手机拍照采集证…

flutter开发实战-build apk名称及指令abiFilters常用gradle设置

flutter开发实战-build apk名称及指令abiFilters常用gradle设置 最近通过打包flutter build apk lib/main.dart --release&#xff0c;发现apk命名规则需要在build.gradle设置。这里记录一下。 一、apk命名规则 在android/app/build.gradle中需要设置 android.applicationVa…

TinyML之Hello world----基于Arduino Nano 33 BLE Sense Rev2的呼吸灯

早期版本的Hello World 这应该是一个逼格比较高的呼吸灯了&#xff0c;用ML来实现呼吸灯功能&#xff0c;之前已经有大佬发过类似的文章&#xff1a;https://blog.csdn.net/weixin_45116099/article/details/126310816 当前版本的Hello World 这是一个ML的入门例程&#xff…

vue3【详解】vue3 比 vue2 升级了哪些重要的功能?

改用 createApp 初始化实例 vue2 使用 new Vue() 初始化实例 vue3 使用 Vue.createApp() 初始化实例 新增 emits 选项 vue3 选项式API中新增了emits 选项&#xff0c;用于显示声明组件中的自定义事件&#xff0c;自定义事件的名称&#xff0c;需用 on 开头。 export default {…

arcgis js 4.x加载SceneLayer并实现基于属性查询定位及高亮

一、代码 <!DOCTYPE html> <html> <head><meta charset"utf-8" /><meta name"viewport" content"widthdevice-width, initial-scale1,maximum-scale1,user-scalableno"><title></title><link rel…

表情识别 | LBP+SVM实现脸部动态特征的人脸表情识别程序(Matlab)

表情识别 | LBPSVM实现脸部动态特征的人脸表情识别程序&#xff08;Matlab&#xff09; 目录 表情识别 | LBPSVM实现脸部动态特征的人脸表情识别程序&#xff08;Matlab&#xff09;预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1 运行环境 程序运行在Windows系统下&am…