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

linux高并发服务器

高并发服务器

高并发服务器

并发服务器开发

1.多进程并发服务器
  使用多进程并发服务器时要考虑以下几点:

  • 父最大文件描述个数(父进程中需要close关闭accept返回的新文件描述符)
  • 系统内创建进程个数(内存大小相关)
  • 进程创建过多是否降低整体服务性能(进程调度)

server

/* server.c */
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include "wrap.h"
#define MAXLINE 80
#define SERV_PORT 8000


void do_sigchild(int num)
{
    waitpid(0, NULL, WNOHANG);
}
int main(void)
{
    struct sockaddr_in servaddr, cliaddr;
    socklen_t cliaddr_len;
    int listenfd, connfd;
    char buf[MAXLINE];
    char str[INET_ADDRSTRLEN];
    int i, n;
    pid_t pid;
    struct sigaction newact;
    newact.sa_handler = do_sigchild;
    sigemptyset(&newact.sa_mask);
    newact.sa_flags = 0;
    sigaction(SIGCHLD, &newact, NULL);
    listenfd = Socket(AF_INET, SOCK_STREAM, 0);
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);
    Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    Listen(listenfd, 20);
    printf("Accepting connections ...\n");
    while (1) {
        cliaddr_len = sizeof(cliaddr);
        connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);
               //多进程服务器
        pid = fork();
        if (pid == 0) {
                        //子进程
            Close(listenfd);
            while (1) {//可以循环读
                n = Read(connfd, buf, MAXLINE);
                if (n == 0) {
                    printf("the other side has been closed.\n");
                    break;
                }
                printf("received from %s at PORT %d\n",
                    inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
                    ntohs(cliaddr.sin_port));
                for (i = 0; i < n; i++)
                    buf[i] = toupper(buf[i]);
                Write(connfd, buf, n);
            }
            Close(connfd);//若不关长期以往会导致文见文件描述符关闭
            return 0;
        }
        else if (pid > 0) {
            Close(connfd);
        }
        else
            perr_exit("fork");
    }
}
 

 

client

 

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include "wrap.h"
#define MAXLINE 80
#define SERV_PORT 8000
int main(int argc, char *argv[])
{
    struct sockaddr_in servaddr;
    char buf[MAXLINE];
    int sockfd, n;
    sockfd = Socket(AF_INET, SOCK_STREAM, 0);
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
    servaddr.sin_port = htons(SERV_PORT);
    Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    while (fgets(buf, MAXLINE, stdin) != NULL) {
        Write(sockfd, buf, strlen(buf));
        n = Read(sockfd, buf, MAXLINE);
        if (n == 0)
            printf("the other side has been closed.\n");
        else
            Write(STDOUT_FILENO, buf, n);
    }
    Close(sockfd);
    return 0;
}

 

2.多线程并发服务器
  在使用线程模型开发服务器时需考虑以下问题:

  • 调整进程内最大文件描述符上限
  • 线程如有共享数据,考虑线程同步
  • 服务于客户端线程退出时,退出处理。(退出值,分离态)
  • 系统负载,随着链接客户端增加,导致其它线程不能及时得到CPU

多线程

 server

/* server.c */
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include "wrap.h"
#define MAXLINE 80
#define SERV_PORT 8000
struct s_info {
    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];
    /* 可以在创建线程前设置线程创建属性,设为分离态,哪种效率高内? */
    pthread_detach(pthread_self());
    while (1) {
        n = Read(ts->connfd, buf, MAXLINE);
        if (n == 0) {
            printf("the other side has been closed.\n");
            break;
        }
        printf("received from %s at PORT %d\n",
            inet_ntop(AF_INET, &(*ts).cliaddr.sin_addr, str, sizeof(str)),
            ntohs((*ts).cliaddr.sin_port));
        for (i = 0; i < n; i++)
            buf[i] = toupper(buf[i]);
        Write(ts->connfd, buf, n);
    }
    Close(ts->connfd);
}
int main(void)
{
    struct sockaddr_in servaddr, cliaddr;
    socklen_t cliaddr_len;
    int listenfd, connfd;
    int i = 0;
    pthread_t tid;
    struct s_info ts[383];
    listenfd = Socket(AF_INET, SOCK_STREAM, 0);
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);
    Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    Listen(listenfd, 20);
    printf("Accepting connections ...\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出错处理, 增加服务器稳定性 */
        pthread_create(&tid, NULL, do_work, (void*)&ts[i]);
        i++;
    }
    return 0;
}

 

 

 

 

client

/* client.c */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include "wrap.h"
#define MAXLINE 80
#define SERV_PORT 8000
int main(int argc, char *argv[])
{
    struct sockaddr_in servaddr;
    char buf[MAXLINE];
    int sockfd, n;
    sockfd = Socket(AF_INET, SOCK_STREAM, 0);
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
    servaddr.sin_port = htons(SERV_PORT);
    Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));while (fgets(buf, MAXLINE, stdin) != NULL) {
        Write(sockfd, buf, strlen(buf));
        n = Read(sockfd, buf, MAXLINE);
        if (n == 0)
            printf("the other side has been closed.\n");
        else
            Write(STDOUT_FILENO, buf, n);
    }
    Close(sockfd);
    return 0;
}
 

 

相关文章:

  • HTML平滑缩放显示图片
  • 高并发服务器二
  • RedHat Linux9.0 硬盘安装全攻略
  • 高并发服务器三
  • 企业集成与 Web Services 和 BPEL
  • 解决CAN中断接收数据,需要外界发送两次,才能响应,但是数据还是会响应两次,不会丢数的问题
  • zynq CAN中断发送J1939数据
  • OnMouseWheel
  • FreeRTOS+CLI
  • 你希望成为一名合格的DBA吗?
  • 一个奇怪的语言现象
  • 代码风格重构注意事项
  • 再读J1939协议
  • oracle SQL性能优化
  • J1939术语对照表
  • 【402天】跃迁之路——程序员高效学习方法论探索系列(实验阶段159-2018.03.14)...
  • 08.Android之View事件问题
  • css布局,左右固定中间自适应实现
  • ES6, React, Redux, Webpack写的一个爬 GitHub 的网页
  • JAVA之继承和多态
  • JS数组方法汇总
  • js算法-归并排序(merge_sort)
  • JS专题之继承
  • Linux学习笔记6-使用fdisk进行磁盘管理
  • open-falcon 开发笔记(一):从零开始搭建虚拟服务器和监测环境
  • PV统计优化设计
  • Python3爬取英雄联盟英雄皮肤大图
  • Rancher-k8s加速安装文档
  • spring-boot List转Page
  • vue-router的history模式发布配置
  • 多线程事务回滚
  • 今年的LC3大会没了?
  • 猫头鹰的深夜翻译:Java 2D Graphics, 简单的仿射变换
  • 批量截取pdf文件
  • 小程序 setData 学问多
  • 译米田引理
  • 怎样选择前端框架
  • 《天龙八部3D》Unity技术方案揭秘
  • 基于django的视频点播网站开发-step3-注册登录功能 ...
  • ​DB-Engines 11月数据库排名:PostgreSQL坐稳同期涨幅榜冠军宝座
  • ​无人机石油管道巡检方案新亮点:灵活准确又高效
  • # Apache SeaTunnel 究竟是什么?
  • ${ }的特别功能
  • (4)事件处理——(2)在页面加载的时候执行任务(Performing tasks on page load)...
  • (JS基础)String 类型
  • (PyTorch)TCN和RNN/LSTM/GRU结合实现时间序列预测
  • (保姆级教程)Mysql中索引、触发器、存储过程、存储函数的概念、作用,以及如何使用索引、存储过程,代码操作演示
  • (力扣记录)235. 二叉搜索树的最近公共祖先
  • (删)Java线程同步实现一:synchronzied和wait()/notify()
  • (学习日记)2024.01.19
  • *p=a是把a的值赋给p,p=a是把a的地址赋给p。
  • .md即markdown文件的基本常用编写语法
  • .NET Core MongoDB数据仓储和工作单元模式封装
  • .Net Web窗口页属性
  • .NET 中的轻量级线程安全