• socket通信,server与多客户端通信


    近日研究socket 通信,学习了如下的一篇文章:

    http://blog.csdn.net/dlutcat/article/details/1813933

    (向作者致敬)

    感觉很好,但还有一点不过瘾,就想着能否加点料:增加多个客户端,让他们一起和服务器端通信。

    为了区别各个客户端,把客户端里加入了识别自身hostname的一段。

    修改后的代码如下:

    server :

    #include<netinet/in.h>
    #include<sys/types.h>
    #include<sys/socket.h>
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<unistd.h>
    #include<sys/signal.h>
    #include<sys/wait.h>
    
    #define HELLO_WORLD_SERVER_PORT    6666
    #define LENGTH_OF_LISTEN_QUEUE 20
    #define BUFFER_SIZE 1024
    
    void reaper(int sig){
    int status;
    while(    wait3(&status,WNOHANG,(struct rusage*)0)  >=0   )
            ;
    }
    int main(int argc, char **argv)
    {
        struct sockaddr_in server_addr;
        bzero(&server_addr,sizeof(server_addr));
        server_addr.sin_family = AF_INET;
        server_addr.sin_addr.s_addr = htons(INADDR_ANY);
        server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);
    
        int server_socket = socket(AF_INET,SOCK_STREAM,0);
        if( server_socket < 0){
            printf("Create Socket Failed!");
            exit(1);
        }
    
        if( bind(server_socket,(struct sockaddr*)&server_addr,sizeof(server_addr))){
            printf("Server Bind Port : %d Failed!", HELLO_WORLD_SERVER_PORT);
            exit(1);
        }
    
        fprintf(stderr,"Before Main Process listen.\n");
        if ( listen(server_socket, LENGTH_OF_LISTEN_QUEUE) ){
            printf("Server Listen Failed!");
            exit(1);
        }
        fprintf(stderr, "After Main Process listen.\n");
    
        (void)signal(SIGCHLD,reaper);
       
        while (1){
            struct sockaddr_in client_addr;
            socklen_t length = sizeof(client_addr);
    
            fprintf(stderr,"Before accept. In %d.\n",getpid());
            int new_server_socket = 
               accept(server_socket,(struct sockaddr*)&client_addr,&length);
    
            if ( new_server_socket < 0){
                printf("Server Accept Failed!\n");
                break;
            }
            fprintf(stderr,"After accept. In %d.\n",getpid());
    
            int child_process_pid = fork();         
            if(child_process_pid == 0 ){
    
                fprintf(stderr,"Child. %d born.\n",getpid());
                close(server_socket);
    
                char buffer[BUFFER_SIZE];
                bzero(buffer, BUFFER_SIZE);
                strcpy(buffer,"Hello,World! FromServer! ");
                int pd;
                pd=getpid();
                char cpd[10];
                sprintf(cpd,"%d",pd);
                strcat(buffer,cpd);
                strcat(buffer,"\n");
                
                send(new_server_socket,buffer,BUFFER_SIZE,0);
                bzero(buffer,BUFFER_SIZE);
    
                length = recv(new_server_socket,buffer,BUFFER_SIZE,0);
                if (length < 0){
                    printf("Server Recieve Data Failed!\n");
                    exit(1);
                }
                fprintf(stderr,"got: %s in %d\n",buffer,getpid());
                close(new_server_socket);
                exit(0);        
            }
            else if(child_process_pid > 0)
                close(new_server_socket);
        }
        close(server_socket);
        return 0;
    }

    client:

    #include <netinet/in.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    
    #define HELLO_WORLD_SERVER_PORT    6666
    #define BUFFER_SIZE 1024
    
    void talk_to_server(char ** argv){   
        struct sockaddr_in client_addr;
        bzero(&client_addr,sizeof(client_addr));
        client_addr.sin_family = AF_INET;
        client_addr.sin_addr.s_addr = htons(INADDR_ANY);
        client_addr.sin_port = htons(0);
    
        int client_socket = socket(AF_INET,SOCK_STREAM,0);
        if( client_socket < 0){
            printf("Create Socket Failed!\n");
            exit(1);
        }
    if( bind(client_socket,(struct sockaddr*)&client_addr,sizeof(client_addr))){ printf("Client Bind Port Failed!\n"); exit(1); }
    struct sockaddr_in server_addr; bzero(&server_addr,sizeof(server_addr)); server_addr.sin_family = AF_INET; if(inet_aton(argv[1],&server_addr.sin_addr) == 0) { printf("Server IP Address Error!\n"); exit(1); } server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT); socklen_t server_addr_length = sizeof(server_addr); if( connect( client_socket, (struct sockaddr*)&server_addr, server_addr_length) < 0 ) { printf("Can Not Connect To %s!\n",argv[1]); exit(1); } char buffer[BUFFER_SIZE]; bzero(buffer,BUFFER_SIZE);
    int length = recv( client_socket, buffer,BUFFER_SIZE,0); if(length < 0){ printf("Recieve Data From Server %s Failed!\n", argv[1]); exit(1); } printf("From Server %s :\t%s",argv[1],buffer); bzero(buffer,BUFFER_SIZE); char name[64]; gethostname(name,sizeof(name)); strcpy(buffer,name);
    send(client_socket,buffer,BUFFER_SIZE,
    0); close(client_socket); } int main(int argc, char **argv){ if (argc != 2){ printf("Usage: ./%s ServerIPAddress\n",argv[0]); exit(1); } int i=0; for(i=0; i<10000; i++){ talk_to_server(argv); sleep(10); } return 0; }

    然后,用三个机器,一个跑server,两个跑client。先运行server,再分别跑两个client,结果如下:

    为了方便观察,略作整理:

    Server端运行结果:

    ./con-server.o
    Before Main Process listen. After Main Process listen. Before accept. In
    676. After accept. In 676 Child 678 born. Before accept. In 676. got : post2.gao in 678 After accept. In 676. Child 679 born. Before accept. In 676. got: post3.gao in 679. After accept. In 676. Child 680 born. Before accept. In 676. got: post2.gao in 680. After accept. In 676. Child. 681 born. Before accept. In 676. got: post3.gao in 681
    ......

    两个client端运行结果:

    ./con-client.o  192.168.66.136                    
                        
    From Server 192.168.66.136:  Hello,World! From Server! 678                    
    From Server 192.168.66.136:  Hello,World! From Server! 680 
    ......
    ./con-client.o  192.168.66.136                    
                        
    From Server 192.168.66.136:  Hello,World! From Server! 679                    
    From Server 192.168.66.136:  Hello,World! From Server! 681 
    ......

    这样就成为多个客户端请求Server端。

    此外也可以发现,listen动作不阻塞,accept动作阻塞。

    服务器端主进程每当捕获到一个客户端请求,就fork一个子进程,
    由子进程用 new_server_socket来send 和 recv工作。

    fork子进程后,工作完毕再消除的方法未必理想,今后有机会看看能否事先开一个进程池,来提升效率。

  • 相关阅读:
    Spring AOP 代理创建方式
    VS全局搜索
    uni-app中添加AES加密
    中国菜刀"连接被重置"问题解决
    Windows go get下载包失败问题解决
    搭建vulhub 漏洞环境及安装Docker和docker-compose
    DedeCMS 5.7通用重装漏洞分析
    各就各位,预备,GO!
    ARL资产灯塔系统分组资产导出脚本
    玩《巫师3》需要了解的背景知识
  • 原文地址:https://www.cnblogs.com/gaojian/p/2618642.html
Copyright © 2020-2023  润新知