linux网络编程echo多进程服务器

echo_server 多进程版本

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <memory.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
int sockfd;

void sign_handler(int signo)
{
    pid_t pid;
    int stat;
    if(signo==SIGINT)
    {
        printf("echo server close\n");
        close(sockfd);
        exit(1);
    }
    if(signo==SIGCHLD){
        while((pid=waitpid(-1,&stat,WNOHANG))>0){
            printf("child %d closed\n",pid);
        }
    }
    return ;
}
void out_fd(int fd)
{
    struct sockaddr_in arr;
    socklen_t len=sizeof(arr);
    if(getpeername(fd,(struct sockaddr*)&arr,&len)<0){
        perror("getpeername fail\n");
        exit(1);
    }
    char ip[16];
    memset(&ip,0,sizeof(ip));
    inet_ntop(AF_INET,&arr.sin_addr.s_addr,ip,sizeof(ip));
    printf("%s connected\n",ip);
}
void server_do(int fd)
{
    char buffer[BUFSIZ];
    while(1){
        printf("ready to read\n");
        memset(buffer,0,sizeof(buffer));
        ssize_t size;
        if((size=read(fd,buffer,sizeof(buffer)))<0){
            perror("server child read fail\n");
            break;
        }else if(size==0){
            break;
        }else{
            printf("number of received bytes=%ld\n",size);
            buffer[size-1]='\0';
            printf("%s\n",buffer);
            if(write(fd,buffer,size)<0){
                if(errno==EPIPE){
                    break;
                }
                perror("server child write fail\n");
            }
        }
    }
}
int main(int argc,char *argv[])
{
    int fd;
    pid_t pid;
    if(argc<2)
    {
        printf("usage:%s <port>",argv[0]);
        exit(1);
    }
    //注册信号
    if(signal(SIGINT,sign_handler)==SIG_ERR){
        perror("signal sigint error\n");
        exit(1);
    }
    if(signal(SIGCHLD,sign_handler)==SIG_ERR){
        perror("signal sigint error\n");
        exit(1);
    }
    /*create socket*/
    sockfd=socket(AF_INET,SOCK_STREAM,0);
    if(sockfd<0){
        perror("socket create fail\n");
        exit(1);
    }
    /*bind socket*/
    struct sockaddr_in serveraddr;
    serveraddr.sin_family=AF_INET;
    serveraddr.sin_port=htons(atoi(argv[1]));
    serveraddr.sin_addr.s_addr=INADDR_ANY;
    if(bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<0){
        perror("socket bind fail\n");
        exit(1);
    } 
    if(listen(sockfd,10)<0){
        perror("socket listen fail\n");
        exit(1);
    }
    /*accept*/
    while(1){
        if((fd=accept(sockfd,NULL,NULL))<0){
            if(errno==EINTR){
                continue;
            }
            perror("socket accept fail\n");
        }
        pid_t pid=fork();
        if((pid=fork())<0){
            perror("fork fail\n");
            continue;
        }else if(pid==0){
            close(sockfd);
            out_fd(fd);
            server_do(fd);
            exit(0);
        }
        close(fd);
    }
    return 0;
}

echo_client

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <memory.h>
#include <signal.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int sockfd;

void cli_do(int sockfd)
{

/*双向通信*/ char buffer[BUFSIZ];
    char *promat=">";
    size_t size;
    while(1){
        memset(buffer,0,sizeof(buffer)); write(STDOUT_FILENO,promat,1); if((size=read(STDIN_FILENO,buffer,sizeof(buffer))>0){ if(size<0) continue; buffer[size-1]='\0';
}else if(size==0){
       continue;
     } if(write(sockfd,buffer,size)>0){ if(read(sockfd,buffer,sizeof(buffer))>0){ printf("%s\n",buffer); } } }
}
int main(int argc,char *argv[]) { if(argc<3){ printf("usage:%s <ip><port>",argv[0]); exit(1); } /*create socket*/ sockfd=socket(AF_INET,SOCK_STREAM,0); if(sockfd<0){ perror("socket create fail\n"); } struct sockaddr_in serveraddr; serveraddr.sin_family=AF_INET; serveraddr.sin_port=htons(atoi(argv[2])); inet_pton(AF_INET,argv[1],&serveraddr.sin_addr.s_addr); if(connect(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<0){ perror("server connect fail\n"); exit(1); } cli_do(sockfd); close(sockfd); return 0; }

 echo客户机改进:

客户机read阻塞与stdin时,如果此时服务器断开连接,服务器给客户机发送一个FIN,但是客户机此时阻塞与标准输入,它将看不到这个EOF

所以进程需要一个预先告知内核能力,使得内核一旦发现进程指定一个或者多个I/O条件就绪 ,它就通知进程,这个能力称为I/O多路复用

所以客户端cli_do改用select方式

cli_do修订

void cli_do(int sockfd)
{
    char buffer[BUFSIZ];
    char *promat=">";
    size_t size;
    fd_set rset;
    FD_ZERO(&rset);
    while(1){
        //select系统调用设置
        FD_SET(sockfd,&rset);
        FD_SET(STDIN_FILENO,&rset);
        //设置select就绪事件 
        if(select(sockfd+1,&rset,NULL,NULL,NULL)<0){
            perror("select close\n");
            break;
        }
        if(FD_ISSET(STDIN_FILENO,&rset)){/*input is readable*/
            if((size=read(STDIN_FILENO,buffer,sizeof(buffer))>0{
               buffer[size-1]='\0';
       }
write(sockfd,buffer,size) } if(FD_ISSET(sockfd,&rset)){/*socket is readable*/ if((size=read(sockfd,buffer,sizeof(buffer))==0){//服务端发送FIN过来 perror("server connect close\n"); break; }else{ printf("%s\n",buffer); } } } }

 echo客户端改进:

这种客户端--服务端   应-答  模式全双工管道数据并没有写满,存在空间的极大浪费

我们改用 批量输入-批量应答  模式

使用select 和shutdown 函数,前者能接收到服务器关闭时的通知,后者运行我们批量输入

cli_do修订

 

void cli_do(int sockfd)
{
    int stdineof;
    char buffer[BUFSIZ];
    char *promat=">";
    size_t size;
    fd_set rset;
    
    FD_ZERO(&rset);
    stdineof=0;
    while(1){
        write(STDOUT_FILENO,promat,1);
        //select系统调用设置
        FD_SET(sockfd,&rset);
        if(stdineof==0) FD_SET(STDIN_FILENO,&rset);
        //设置select就绪事件 
        if(select(sockfd+1,&rset,NULL,NULL,NULL)<0){
            perror("select close\n");
            break;
        }
        if(FD_ISSET(STDIN_FILENO,&rset)){/*input is readable*/
            if((size=read(STDIN_FILENO,buffer,sizeof(buffer)))==0){
                stdineof=1;
                shutdown(sockfd,SHUT_WR);/*send FIN*/
                FD_CLR(STDIN_FILENO,&rset);
                continue;
            }
            buffer[size-1]='\0';
            write(sockfd,buffer,size);
        }
        if(FD_ISSET(sockfd,&rset)){/*socket is readable*/
            if((size=read(sockfd,buffer,sizeof(buffer)))==0){
                if(stdineof==1){
                    return;
                }else{
                    perror("server terminated prematurely\n");
            break; } } printf(
"%s\n",buffer); } } }

 使用I/O复用模型  单进程 select 就绪事件监听描述符集 修改echo_server

echo_server 修订版

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <memory.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <sys/select.h>
int sockfd;

void sign_handler(int signo)
{
    pid_t pid;
    int stat;
    if(signo==SIGINT)
    {
        printf("echo server close\n");
        close(sockfd);
        exit(1);
    }
    if(signo==SIGCHLD){
        printf("client close\n");
        wait(0);
    }
    return ;
}
void out_fd(int fd)
{
    struct sockaddr_in arr;
    socklen_t len=sizeof(arr);
    if(getpeername(fd,(struct sockaddr*)&arr,&len)<0){
        perror("getpeername fail\n");
        exit(1);
    }
    char ip[16];
    memset(&ip,0,sizeof(ip));
    inet_ntop(AF_INET,&arr.sin_addr.s_addr,ip,sizeof(ip));
    printf("%s connected\n",ip);
}

int main(int argc,char *argv[])
{
    int fd;
    pid_t pid;
    if(argc<2)
    {
        printf("usage:%s <port>",argv[0]);
        exit(1);
    }
    //注册信号
    if(signal(SIGINT,sign_handler)==SIG_ERR){
        perror("signal sigint error\n");
        exit(1);
    }
    if(signal(SIGCHLD,sign_handler)==SIG_ERR){
        perror("signal sigint error\n");
        exit(1);
    }
    /*create socket*/
    sockfd=socket(AF_INET,SOCK_STREAM,0);
    if(sockfd<0){
        perror("socket create fail\n");
        exit(1);
    }
    /*bind socket*/
    struct sockaddr_in serveraddr,cliaddr;
    serveraddr.sin_family=AF_INET;
    serveraddr.sin_port=htons(atoi(argv[1]));
    serveraddr.sin_addr.s_addr=INADDR_ANY;
    if(bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<0){
        perror("socket bind fail\n");
        exit(1);
    } 
    if(listen(sockfd,10)<0){
        perror("socket listen fail\n");
        exit(1);
    }
    /*accept*/
    int i,maxfd,maxi,connfd,clientfd;
    int nready,client[FD_SETSIZE];
    ssize_t size;
    fd_set rset,allset;
    char buffer[BUFSIZ];
    socklen_t clien;

    maxfd=sockfd;
    maxi=-1;/*index into client[] array*/
    for(i=0;i<FD_SETSIZE;i++){
        client[i]=-1;
    }
    FD_ZERO(&allset);
    FD_SET(sockfd,&allset);
    for(;;){
        rset=allset;
        nready=select(maxfd+1,&rset,NULL,NULL,NULL);
        
        if(FD_ISSET(sockfd,&rset)){/*new client connection*/
            clien=sizeof(cliaddr);
            if((connfd=accept(sockfd,(struct sockaddr*)&cliaddr,&clien))>0){
                out_fd(connfd);
            }
            for(i=0;i<FD_SETSIZE;i++){
                if(client[i]<0){
                    client[i]=connfd;
                    break;
                }
            }
            if(i==FD_SETSIZE){
                perror("too many clients\n");
            }
            FD_SET(connfd,&allset);//添加新的监听就绪事件
            if(connfd>maxfd) maxfd=connfd;
            if(i>maxi) maxi=i; 
            if(--nready<=0) continue;
        }
        for(i=0;i<=maxi;i++){/*check all clients for data*/
            if((clientfd=client[i])<0) continue;
            if(FD_ISSET(clientfd,&rset)){
                printf("ready to read\n");
                if((size=read(clientfd,buffer,sizeof(buffer)))==0){//接受到EOF,client已经关闭
                    close(clientfd);
                    FD_CLR(clientfd,&allset); 
                    client[i]=-1;
                }else{
                    printf("%s\n",buffer);
                    write(clientfd,buffer,size);
                    if(--nready<=0) break;
                }
            }

        }
    }
}

 poll系统调用

void cli_do(int sockfd)
{
    int stdineof;
    char buffer[BUFSIZ];
    char *promat=">";
    size_t size;
    fd_set rset;
    
    FD_ZERO(&rset);
    stdineof=0;
    while(1){
        write(STDOUT_FILENO,promat,1);
        //select系统调用设置
        FD_SET(sockfd,&rset);
        if(stdineof==0) FD_SET(STDIN_FILENO,&rset);
        //设置select就绪事件 
        if(select(sockfd+1,&rset,NULL,NULL,NULL)<0){
            perror("select close\n");
            break;
        }
        if(FD_ISSET(STDIN_FILENO,&rset)){/*input is readable*/
            if((size=read(STDIN_FILENO,buffer,sizeof(buffer)))==0){
                stdineof=1;
                shutdown(sockfd,SHUT_WR);/*send FIN*/
                FD_CLR(STDIN_FILENO,&rset);
                continue;
            }
            buffer[size-1]='\0';
            write(sockfd,buffer,size);
        }
        if(FD_ISSET(sockfd,&rset)){/*socket is readable*/
            if((size=read(sockfd,buffer,sizeof(buffer)))==0){
                if(stdineof==1){
                    return;
                }else{
                    perror("server terminated prematurely\n");
                    break;
                }
            }
            printf("%s\n",buffer);
        }
    }
}

echo_server

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <memory.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <poll.h>

int sockfd;

void sign_handler(int signo)
{
    pid_t pid;
    int stat;
    if(signo==SIGINT)
    {
        printf("echo server close\n");
        close(sockfd);
        exit(1);
    }
    if(signo==SIGCHLD){
        printf("client close\n");
        wait(0);
    }
    return;
}
void out_fd(int fd)
{
    struct sockaddr_in arr;
    socklen_t len=sizeof(arr);
    if(getpeername(fd,(struct sockaddr*)&arr,&len)<0){
        perror("getpeername fail\n");
        exit(1);
    }
    char ip[16];
    
    memset(&ip,0,sizeof(ip));
    inet_ntop(AF_INET,&arr.sin_addr.s_addr,ip,sizeof(ip));
    printf("%s connected\n",ip);
}

int main(int argc,char *argv[])
{
    printf("tsest");
    
    if(argc<2)
    {
        printf("usage:%s <port>",argv[0]);
        exit(1);
    }
    //注册信号
    if(signal(SIGINT,sign_handler)==SIG_ERR){
        perror("signal sigint error\n");
        exit(1);
    }
    if(signal(SIGCHLD,sign_handler)==SIG_ERR){
        perror("signal sigint error\n");
        exit(1);
    }
    /*create socket*/
    sockfd=socket(AF_INET,SOCK_STREAM,0);
    if(sockfd<0){
        perror("socket create fail\n");
        exit(1);
    }
    /*bind socket*/
    struct sockaddr_in serveraddr,cliaddr;
    serveraddr.sin_family=AF_INET;
    serveraddr.sin_port=htons(atoi(argv[1]));
    serveraddr.sin_addr.s_addr=INADDR_ANY;
    if(bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<0){
        perror("socket bind fail\n");
        exit(1);
    } 
    if(listen(sockfd,10)<0){
        perror("socket listen fail\n");
        exit(1);
    }    
    /*poll系统调用*/
    int i,maxfd,maxi,connfd,clientfd,nready,open_max;
    ssize_t size;
    char buffer[BUFSIZ];
    socklen_t clien;
    open_max=sysconf(_SC_OPEN_MAX);
    
    struct pollfd client[open_max];
    client[0].fd=sockfd;
    client[0].events=POLLRDNORM;
    for(i=0;i<open_max;i++) client[i].fd=-1;
    maxi=0;
 
    for(;;){
        nready=poll(client,maxi+1,0);
        
        if(client[0].revents & POLLRDNORM){/*new client connection*/
            printf("werwerew");
            break;
            clien=sizeof(cliaddr);
            if((connfd=accept(sockfd,(struct sockaddr*)&cliaddr,&clien))>0) out_fd(connfd);
            
            for(i=0;i<open_max;i++){
                if(client[i].fd<0){
                    client[i].fd=connfd;
                    break;
                }
            }
            if(i==open_max) perror("too many clients\n");
            client[i].events=POLLRDNORM;//添加新的监听就绪事件
            if(i>maxi) maxi=i; 
            if(--nready<=0) continue;
        }
        for(i=0;i<=maxi;i++){/*check all clients for data*/
            if((clientfd=client[i].fd)<0) continue;
            if(client[i].revents&(POLLRDNORM|POLLERR)){
                printf("ready to read\n");
                break;
                if((size=read(clientfd,buffer,sizeof(buffer)))==0){//接受到EOF,client已经关闭
                    close(clientfd); 
                    client[i].fd=-1;
                }else{
                    printf("%s\n",buffer);
                    write(clientfd,buffer,size);
                    if(--nready<=0) break;
                }
            }

        }
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/peixiguang/p/6035215.html

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值