zoukankan      html  css  js  c++  java
  • 多进程并发服务器

    本实验基于Linux平台下的C语言编程实现

    1.服务器端程序设计步骤:

       1)使用socket()函数创建套接字;

       2)将创建的套接字绑定到指定的地址结构;

       3)listen()函数设置套接字为侦听模式,使服务器处于打开状态;

       4)接受客户端的连接请求,建立连接;

       5)接收、应答客户端的数据请求;

       6)终止连接。

    2. 客户端程序设计步骤:

       1)使用socket()函数创建套接字;

       2)调用connect()函数建立一个与TCP服务器的连接;

       3)发送数据请求,接收服务器的数据应答;

       6)终止连接。

    代码:

    //客户端:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #define MAXDATASIZE 1000
    #define PORT 1234
    int main(int argc,char **argv){
        int listenfd,nbytes;
        struct sockaddr_in srvaddr;
        char buf[MAXDATASIZE];
        int i=1;
        //使用socket()函数创建套接字
        listenfd=socket(AF_INET,SOCK_STREAM,0); //listenfd侦听套接字,SOCK_STREAM流式套接字
        if(listenfd==-1){
            printf("create socket failed !
    ");
            exit(1);
        }
        //指定服务器地址(本地socket地址采用默认值)
        bzero(&srvaddr,sizeof(srvaddr));  //初始化
        srvaddr.sin_family=AF_INET;  //IPv4
        srvaddr.sin_port=htons(PORT); //htons:host to net long
        //将字符串形式的IP地址转换成32网络字节序的IP地址
        if(inet_aton("127.0.0.1",srvaddr.sin_addr.s_addr)==-1){
            printf("addr convert error !
    ");
            exit(1);
        }
        //调用connect()函数建立一个与TCP服务器的连接
        if(connect(listenfd,(struct sockaddr *)&srvaddr,sizeof(struct sockaddr))==-1){
            printf("connect error !
    ");
            exit(1);
        }
        //接收服务器的数据应答
        //recv()函数前三个参数与read()函数一致,第四个参数为0时与read()相同
        if((nbytes=recv(listenfd,buf,MAXDATASIZE,0))==-1){
            printf("read error !
    ");
            exit(1);
        }
        buf[nbytes]='';
        printf("Server Massage: %s
    ",buf);
        printf("Input your name: ");  //提示输入客户姓名,用来区分不同的客户
        scanf("%s",buf);
        if((nbytes=send(listenfd,buf,strlen(buf),0))==-1){
            perror("Send error !
    ");
            exit(1);
        }
        while(i){
            printf("Input message(max char:%d):",MAXDATASIZE);//输入要发给server的消息
            scanf("%s",buf);
            if(strlen(buf)<1)
                i=0;
            if((nbytes=send(listenfd,buf,strlen(buf),0))==-1){//发送消息
                perror("Send error !
    ");
                exit(1);
            }
            if((nbytes=recv(listenfd,buf,MAXDATASIZE,0))==-1){//接收server的反馈消息
                perror("read error !
    ");
                exit(1);
            }
            buf[nbytes]='';
            printf("Server message: %s
    ",buf);
            printf("
    ");
        }
        //关闭listenfd
        close(listenfd);
    }
    //服务器端:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #include <arpa/inet.h>
    #define MAXDATASIZE 1000
    #define PORT 1234
    #define BACKLOG 5
    void process_client(int connectfd,struct sockaddr_in client);
    int main(int argc,char **argv){
        int listenfd,connectfd,nbytes,sin_size;
        char buf[MAXDATASIZE];
        int opt=SO_REUSEADDR;
        pid_t pid;
        struct sockaddr_in srvaddr,clientaddr;
        
        //创建网络端点
        listenfd=socket(AF_INET,SOCK_STREAM,0);//listenfd为侦听套接字,SOCK_STREAM流式
        if(listenfd==-1){
            printf("Create socket failed !
    ");
            exit(1);
        }
        //填充地址
        bzero(&srvaddr,sizeof(srvaddr)); //初始化
        srvaddr.sin_family=AF_INET;  //IPv4
        srvaddr.sin_port=htons(PORT); //htons:host to net short
        //将字符串形式的IP地址转换成32网络字节序的IP地址
        if(inet_aton("127.0.0.1",srvaddr.sin_addr.s_addr)==-1){
            printf("addr convert error !
    ");
            exit(1);
        }
        //绑定服务器地址和端口
        if(bind(listenfd,(struct sockaddr *)&srvaddr,sizeof(struct sockaddr))==-1){
            printf("Bind error !
    ");
            exit(1);
        }
        //监听端口
        if(listen(listenfd,BACKLOG)==-1){
            printf("listen error !
    ");
            exit(1);
        }
        while(1){
            //接收客户端的连接请求,建立连接
            if((connectfd=accept(listenfd,(struct sockaddr *)&clientaddr,&sin_size))==-1){
                perror("Accept error !
    ");
                exit(-1);        
            }
            //下面是多进程并发的核心所在
            //用fork()函数创建进程
            if((pid=fork())>0){ //父进程处理过程
                close(connectfd); //父进程关闭已连接描述符
                continue;  //继续接受下一个客户的请求
            }
            else if(pid==0){  //子进程处理过程
           //子进程关闭监听描述符,然后调用process_client()函数处理该客户的请求
                close(listenfd); 
                process_client(connectfd,clientaddr);
                exit(1);  //终止子进程
            }
            else{  //调用失败处理
                perror("Fork error !
    ");
                exit(0);  //退出
            }
        }
        close(listenfd);
    }
    void process_client(int connectfd,struct sockaddr_in client){
        char recvbuf[MAXDATASIZE];
        char client_name[MAXDATASIZE];
        int recvlen,i;
        //显示客户的IP,用inet_ntoa将客户地址转换为可显示的
        printf("You get a connetion from %s
    ",inet_ntoa(client.sin_addr));
        send(connectfd,"Welcome to my server.
    ",22,0);
        //接收客户的名字并显示
        recvlen=recv(connectfd,client_name,MAXDATASIZE,0);
        //对是否已经结束通话进行判断
        if(recvlen==0){
            close(connectfd);
            printf("Client disconnected.
    ");    
            return;
        }
        else if(recvlen<0){
            close(connectfd);
            printf("Connect broked.
    ");
            return;
        }
        client_name[recvlen]='';
        printf("Client name is %s.
    ",client_name);
        //不断重复接收客户的数据,接收成功则显示
        while(recvlen=recv(connectfd,recvbuf,MAXDATASIZE,0)){
            recvbuf[recvlen]='';
            printf("Receive from client<%s> message: %s
    ",client_name,recvbuf);
            recvbuf[recvlen]='';
            send(connectfd,recvbuf,strlen(recvbuf),0);
        }
        printf("Client: %s disconnected.
    ",client_name);
        //关闭connectfd
        close(connectfd);
    }

    运行结果如下:

    ①开启服务器

    服务器端:

     

    ②客户A连接服务器

    客户端A:

     

    服务器端:

     

    ③客户B也连接服务器

    客户端B:

     

    服务器端:

     

    ④客户B发送消息

    客户端B发送hello!

     

    服务器端收到hello!并显示是B发来的:

     

    ⑤客户A发送消息

    客户端A发送thanks.

     

    服务器端接收到thanks.并显示是来自A的消息:

     

    ⑥客户端A断开连接

    客户端退出:

     

    服务器端显示如下:

     

    ⑦客户端B断开连接

    客户端退出:

     

    服务器端显示如下:

     

  • 相关阅读:
    第二次冲刺 03
    第二次冲刺 02
    第二次冲刺 01
    程序员修炼三部曲阅读笔记03
    程序员修炼三部曲阅读笔记02
    团队项目计划会议
    课堂练习—购书
    构建之法阅读笔记03
    学习进度条十二
    课堂作业找水王2
  • 原文地址:https://www.cnblogs.com/yytest/p/12955665.html
Copyright © 2011-2022 走看看