小项目之并发测试(客户端)

本文对很多人来说是没有一点技术可言的,仅仅是记录了自己的学习过程.

要求:

输入:iso_stress -c 5000  -I 500  -f iso.txt  -H 4.2.2.2 -P 8888

-c 5000就是创建5000个线程来连服务器
-I 就是发送的时间间隔为500ms
-f 就是要发送的文件
-H 就是服务器IP地址
-P 指定端口号

然后根据-c指定的个数创建5000个线程,然后连到服务器上,当线程全部创建完成后就开始同时发送-f指定的文件过去,另外每一次发送文件统计一下,发送到接受数据包的时间


程序各个小模块

命令解析模块

   struct option       long_options[] =
    {
        {"thread", require_argument, NULL, 'c'},
        {"time", require_argument, NULL, 'I'},
        {"file",require_argument, NULL, 'f'},
        {"ipaddr", require_argument, NULL,'H'},
        {"port", require_argument, NULL, 'P'},
        {NULL, 0, NULL, 0}
    };


    while ((opt = getopt_long(argc, argv, "c:I:f:H:P:", long_options, NULL)) != -1)
    {
        switch (opt)
        {
            case 'c':
                thread_num = atoi(optarg);
                printf("thread num is [%d].\n", thread_num);
                break;

            case 'I':
                delay_time = atoi(optarg);
                printf("time is [%d].\n", delay_time);
                break;

            case 'f':
                send_file = optarg;
                printf("the send file is [%s].\n", send_file);
                break;

            case 'H':
                serv_ip = optarg;
                printf("the ipaddr is [%s].\n", serv_ip);
                break;

            case 'P': 
               serv_port = atoi(optarg);
                printf("the port is [%d].\n",serv_port);
                break;

            default:
                break;
        }
    }

初始化打开文件数限制

int network_init(void)
{
    struct rlimit rlt;

    rlt.rlim_max = rlt.rlim_cur = 5000;
    if (setrlimit(RLIMIT_NOFILE, &rlt) != 0)
    {
        printf("setrlimit failure: %s\n", strerror(errno));
        return -1;
    }

    return 0;
}

信号控制

void signal_handler(int signo)
{
    switch(signo)
    {
        case SIGTERM:
        case SIGINT:
            printf("program pid [%d] receive SIGINT/SIGTERM signal, exit program now\n", getpid());
            g_stop = 1;
            break;

        case SIGSEGV:
            printf("program pid [%d] SIGSEGV signal, exit program now\n", getpid());
            g_stop = 1;
            break;
            
        case SIGPIPE:
            printf("program pid [%d] SIGPIPE signal, exit program now\n", getpid());
            g_stop = 1;
            break;
            
        default:
            printf("program pid [%d] receive signal [%d]. \n", getpid(), signo);
            break;
    }       
            
    return;
}

void install_signal(void)
{
    struct sigaction sigact, sigin;
    printf("Install signal action\n");

    /* initialize the catch signal */
    sigemptyset(&sigact.sa_mask);
    sigact.sa_flags = 0;
    sigact.sa_handler = signal_handler;

    /* setup the ignore signal */
    sigemptyset(&sigin.sa_mask);
    sigin.sa_flags = 0;
    sigin.sa_handler = SIG_IGN;

    sigaction(SIGTERM, &sigact, 0); /*  catch terminate signal "kill" command */
    sigaction(SIGINT, &sigact, 0);  /*  catch interrupt signal CTRL+C */
    sigaction(SIGCHLD, &sigact, 0); /*  catch child process return */
    sigaction(SIGPIPE, &sigact, 0); /*  catch broken pipe */

    return;
}

取读取文件长度

int get_file_size(const char *path_file)
{
    int          fd;
    struct stat  get_size_buf;

    if ((fd = open(path_file, O_RDONLY)) < 0)
    {
        printf("open the file and get file size  failure: %s\n", strerror(errno));
        return -1;
    }

    if (fstat(fd, &get_size_buf) != 0)
    {
        printf("get the file size failure: %s\n", strerror(errno));
        return -1;
    }

    close(fd);
    return get_size_buf.st_size;

}

获取文件数据并转换成十六进制数(要求)

void get_file_data(const char *path_file, unsigned char *get_data_buf, int file_size)
{
    assert(path_file != NULL);
    assert(get_data_buf != NULL);
    assert(&file_size != NULL);

    size_t          size;
    int             len;
    int             fd;
    int             i;
    char            buf[3];
    unsigned char   hex_buf[1024];


    memset(buf, 0, sizeof(buf));
    if ((fd = open(path_file, O_RDONLY)) < 0)
    {
        printf("open the file failure and read data failure: %s\n", strerror(errno));
        return ;
    }

    if ((size = read(fd, get_data_buf, file_size)) <= 0)
    {
        printf("read data from file failure: %s\n", strerror(errno));
        return ;
    }

    /* change sixteen string to ten */
    for (i=0; i<file_size/2; i++)
    {
        buf[0] = get_data_buf[i*2];
        buf[1] = get_data_buf[i*2+1];

        get_data_buf[i] = strtol(buf, NULL, 16);
    }

    close(fd);
    return ;
}

简单的输出函数

print_hex_string(char *buf, int len)
{   
    int     i;
    for (i=0; i<len; i++)
        printf("data[%d] = 0x%02X\n", i, buf[i]);
}

处理线程函数

void *thread_func(void *thread_arg)
{
    assert(thread_arg != NULL);

    int                     sockfd;
    int                     nsize;
    int                     rv = 0;
    int                     opt = 1;
    struct sockaddr_in      serv_addr;
    char                    buf[1024];
    int                     count;
    THREAD_ARG      *arg = (THREAD_ARG *)thread_arg;


    count = ++arg->thread_count;
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        printf("use socket failure: %s\n", strerror(errno));
        return NULL;
    }

    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(arg->port);
    if (inet_pton(AF_INET, arg->ipaddr, &serv_addr.sin_addr) < 0)
    {
        printf("inet_pton failure: %s\n", strerror(errno));
        return NULL;
    }

    if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) < 0)
    {
        printf("connect to server failure: %s\n", strerror(errno));
        return NULL;
    }
    printf("the thread [%d] is connect to server.\n",count);

    /* set the flag, if flag is 1, send data */
    while (g_thread_start_flag != 1)
        ;

    while (!g_stop)
    {
        /* send data every 500ms */
        nanosleep(&(arg->delay_time), NULL);

        /* record time when send the data  */
        struct timeval      now;
        int                 rc;
        double              start_send, recv_end;

        if ((rc = gettimeofday(&now, NULL)) != 0)
        {
            printf("get the time when send data failure\n");
            continue;
        }
        start_send = now.tv_sec + (now.tv_usec / 1000000.0);

        /* send the data */
        nsize = arg->size;
        printf("thread [%d] send %d bytes data to server.\n",count,nsize);
        while(nsize > 0)
        {
            rv= write(sockfd, arg->data, nsize);
            if (rv < 0)
            {
                printf("write() to server failure: %s\n", strerror(errno));
                return NULL;
            }

            nsize -= rv;
        }

        if((nsize = read(sockfd, buf, sizeof(buf))) < 0)
        {
            printf("read failure: %s\n", strerror(errno));
            return NULL;
        }
        else
        {
            printf("thread [%d] receive [%d] bytes data from server.\n", count, nsize);
            print_hex_string(buf, nsize);
        }
       if ((rc = gettimeofday(&now, NULL)) != 0)
        {
            printf("get the time when received data failure\n");
        
        }   
        recv_end = now.tv_sec + (now.tv_usec / 1000000.0);
        printf("%.6lfs interval for send and receive.\n", recv_end - start_send);

    } /* while(1) */

    printf("thread [%d] exit now\n ", count);

    --arg->thread_count;
    close(sockfd);
    pthread_exit(NULL);
    return NULL;
}

主函数中一些初始化

    /* initialize time */
    slptime.tv_sec = 0;
    slptime.tv_nsec = (delay_time * 1000000); /* 500ms */ /* error */


    /* get file size and get file data */
    file_size = get_file_size(send_file);
    get_data_buf = (char *)malloc(sizeof(char) * (file_size + 1));
    get_file_data(send_file, get_data_buf, file_size);

    /* initialize thread_reg */
    thread_arg.num = thread_num;
    thread_arg.delay_time = slptime;
    thread_arg.data = get_data_buf;
    thread_arg.size = file_size/2;
    thread_arg.ipaddr = serv_ip;
    thread_arg.port = serv_port;

    /* intialize network  */
    network_init();

    for (i=0; i<thread_num; i++)
    {
        err = pthread_create(&tid[i], NULL, thread_func, (void *)&thread_arg);
        if (err != 0)
        {
            printf("the thread [%d] is create failure: %s\n", i+1, strerror(err));

        }
        printf("create [%d] thread successfully.\n", i+1);
    }
    g_thread_start_flag = 1;

    for(i=0; i<thread_num;i++)
    {
        err = pthread_join(tid[i], NULL);
        printf("can't get thread [%d] exit.\n", i);
    }

    return 0;

一个不大的程序,却能从其中学到很多东西.比如:

(1) 多线程中尽量不要使用sleep() 因为它是非线程安全函数

(2) 关于TCP socket中读取字节需要注意的一些因素 http://www.360doc.com/content/11/0731/10/2127922_136887195.shtml

当然,我显然没按照上面的文章里面说的去做...因为要求的关系没有用到.以后再借鉴

(3)进一步了解了多线程的编程,但是还需要更多的努力.

(4)懂得用GDB进行一些初级的调试.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值