多进程并发服务器C++实现字符串小写到大写转换

多进程并发服务器

在这里插入图片描述
       服务器server执行accept函数等待客户端A,B,C,D与之建立连接,假设客户端A与服务器建立连接时,服务器在就创建一个子进程,子进程负责与客户端A进行数据交互, (如果其他客户端再与服务器进行连接,而服务器忙着与A进行数据交互,则不会顾及其他客户端,这也是他的缺点),而父进程则继续监听其他客户端,当其他客户端进行连接时,服务器再创建一个新的子进程与之进行交互.

       当父进程与与客户端连接完成后,会产生一个cfd和lfd , 当fork()产生一个子进程时,则会将这个cfd与lfd 继承,cfd可以用于与客户端进行数据交互,而lfd对于子进程来说并没有用处,所以子进程要将继承的lfd关闭.对于父进程来说父进程不需要与其他客户端进行数据交互,所以父进程需要关闭cfd.

       子进程完成与客户端的数据交互后,子进程会退出变成僵尸进程,所以父进程要对子进程进行回收.可以用回调机制,利用信号进行处理:利用SIGCHLD注册信号捕捉函数,在捕捉函数内调用waitpid()回收子进程

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

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

多线程高并发服务器实现将字符串转化大写

       客户端往服务器端发送字符串,服务器把字符串转换成大写之后再发送回给客户端。

大致流程:

在这里插入图片描述

server.cpp

#include <iostream>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include <ctype.h>
#include <strings.h>
#include <assert.h>
using namespace std;

#define MAXLINE 4096
#define SERV_PORT 8000
//信号捕捉函数,信号:SIGCHLD:当子进程状态发生变化(退出或暂停)时产生
void do_sigchild(int num){
    
    
    while(waitpid(0,NULL,WNOHANG) > 0){
    
    //回收子进程
    }
}


int main(){
    
    
    struct sockaddr_in servaddr,cliaddr;
    socklen_t cliaddr_len = sizeof(cliaddr);
    int listenfd,connfd;
    char buf[MAXLINE];
    char str[INET_ADDRSTRLEN];
    
    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);
    assert(listenfd >= 0);
	//重用本地地址,socket之后bind之前
    int opt = 1;
    setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));

    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);

    int ret = bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr));
    assert(ret != -1);

    ret = listen(listenfd,20);
    assert(ret != -1);

    cout << "Accepting connections ..." << endl;
    while(1){
    
    
        connfd = accept(listenfd,(struct sockaddr*)&cliaddr,&cliaddr_len);
        pid_t pid = fork();
        if(pid == 0){
    
    
            close(listenfd);//子进程将继承得来的listenfd关闭
            while(1){
    
    
                int n = read(connfd,buf,MAXLINE);//读取客户端数据
                if(n == 0){
    
    
                    cout << "the other side has been closed. " << endl;
                    break;
                }
                //输出客户端IP地址和PORT
                cout << "Received from " 
                    << inet_ntop(AF_INET,&cliaddr.sin_addr,str,sizeof(str))
                    << " at POTR "
                    << ntohs(cliaddr.sin_port)
                    << endl;
                //将小写转换为大写
                for(int i = 0;i < n;i++){
    
    
                    buf[i] = toupper(buf[i]);
                }
                write(STDOUT_FILENO,buf,n);//输出到服务器的屏幕
                write(connfd,buf,n);//输出到客户端
            }
            close(connfd);
            return 0;
        }else if(pid > 0){
    
    
            close(connfd);//父进程不需要与客户端进行数据交互,所以关闭connfd
        }else{
    
    
            perror("fork error");
        }
    }
    return 0;
}

client.cpp

#include <iostream>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <strings.h>
#include <string.h>
using namespace std;
#define SERV_PORT 8000
#define MAXLINE 4096
int main(){
    
    
    
    struct sockaddr_in servaddr;
    char buf[MAXLINE];

    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    assert(sockfd >= 0);

    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(SERV_PORT);
    inet_pton(AF_INET,"127.0.0.1",&servaddr.sin_addr);
    
    int ret = connect(sockfd,(struct sockaddr*)&servaddr,sizeof(sockaddr));
    if(ret < 0){
    
    
        perror("connect error ");
        exit(1);
    }
	
    while(fgets(buf,MAXLINE,stdin) != NULL){
    
    //读取键盘数据
        write(sockfd,buf,strlen(buf));//将数据写到服务器
        int n = read(sockfd,buf,MAXLINE);//从服务器读取数据
        if(n == 0){
    
    
            cout << "the other side has been closed" << endl;
            break;
        }else{
    
    
            write(STDOUT_FILENO,buf,n);//将从服务器读到的数据显示到客户端屏幕上
        }
    }
    close(sockfd);

    return 0;
}

Guess you like

Origin blog.csdn.net/weixin_44515978/article/details/119842012