fastdfs多线程长连接

这是一个使用C语言实现的FastDFS多线程压力测试工具,用于模拟上传文件操作。程序通过命令行参数配置线程数、每个线程的请求次数,并支持连接池管理,以提高上传效率。

//压力测试工具,分多进程和多线程两种场景
#include <errno.h>
#include <pthread.h>
#include <signal.h>

#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "fdfs_client.h"
#include "fdfs_global.h"
#include "fdfs_base64.h"
#include "logger.h"

void
TestUsage ( int iIsThread,char *argv[] )
{
    if(iIsThread)
    {
        printf ( "Usage: %s -t ThreadCount -c SendCountPerThread /n", argv[0] );
        printf("<conf operation>/n" /
                "/toperation: upload, download, getmeta, setmeta, " /
                "delete and query_servers/n", argv[0]);
        printf ( "e.g.:  %s -t 30 -c 100 ../conf/client.conf upload file/n", argv[0] );
    }
    else
    {
        printf ( "Usage: %s -t ProcessCount -c SendCountPerProcess/n", argv[0] );
        printf("<conf operation>/n" /
                "/toperation: upload, download, getmeta, setmeta, " /
                "delete and query_servers/n", argv[0]);
        printf ( "e.g.:  %s -t 30 -c 100 ../conf/client.conf upload file/n", argv[0] );
    }
}

static int nSum = 0,nTradeOK=0,nTradeFailed=0;
static int OverThread = 0;
int nThreadCount=1,nReqCount=1,nTimeAllUsed=0;
static pthread_mutex_t theSumMutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t theConnMutex = PTHREAD_MUTEX_INITIALIZER;
char server[16]={0};
int port;

char operation[64]={0};
char conf_filename[64]={0};
char local_filename[64]={0};

//typedef void * (*ThreadFunction)(void *pParam);
int CreateThread(void *(* pFunction)(void *), void *pParam)
{
    int nReturn = 0;
    pthread_t tid;

    if(pthread_create(&tid, NULL, pFunction, pParam) != 0)
    {
        return(0);
    }

    pthread_detach(tid);

    nReturn = (int)tid;

    if( nReturn <-1 )
    {
        return 1024;
    }
    else
    {
        return(nReturn);
    }
}

// befor you definition you would be user ,mast have state.
void StartApp (  );

int main ( int argc, char **argv )
{
    int n;

    if (argc <= 6)
    {
        TestUsage(1,argv);
        exit(1);
    } 
    if (strchr(argv[1], '-') == NULL)
    {
        TestUsage(1,argv);
        exit(1);
    }

    for ( n = 1; n < argc; ++n )
    {
        // read garam from command,for create number of  thread
        if ( strcmp ( argv[n], "-t" ) == 0 )
        {
            n++;
            nThreadCount=atoi ( argv[n] );
        }
        // read garam from command, for total every thread has how mutch request
        else if ( strcmp ( argv[n], "-c" ) == 0 )
        {
            n++;
            nReqCount =atoi ( argv[n] );
        }
    }

    strncpy(conf_filename,argv[5],64);
    strncpy(operation,argv[6],64);
    strncpy(local_filename,argv[7],64);

    printf(" INFO: multithreading test about to FastDFS starting..../n");
    printf(" INFO: conf_filename=%s,operation=%s,local_filename=%s/n",/
            conf_filename,operation,local_filename);

    //start the spp
    StartApp ( );
    printf(" INFO: you operate is all over ,you can checke the result! /n");
    return ( 0 );
}

// thread to call this funcation
void * MultiThreadTest( void *pParam )
{
    int MessageSum = 0;
    memcpy( &MessageSum, pParam, 4);

    int nStartTime = time(NULL);
    int nReqStartTime = 0, nReqEndTime = 0, nTimeout = 0;

    TrackerServerInfo theTrackerServer;
    memset( &theTrackerServer, 0, sizeof(theTrackerServer) );
    TrackerServerInfo *pTrackerServer = &theTrackerServer;

    int result = 0;
    TrackerServerInfo storageServer;
    char group_name[FDFS_GROUP_NAME_MAX_LEN + 1];
    char remote_filename[256];
    char buff[32];
    char token[32 + 1];
    char file_id[128];
    char file_url[256];
    int len = 0;
    int url_len = 0;
    time_t ts;
    char *file_buff;
    int64_t file_size;
    char *meta_buff;
    int store_path_index = 0;
    struct base64_context context;
    nReqStartTime=time(NULL);

    //为了最后解析出文件大小需要初始化这个变量
    base64_init_ex(&context, 0, '-', '_', '.');   
    printf( "DEBUG :base64_init_ex ok/n");

    int i=0;//发送数目
    //处理在线请求时可以改成while(Running)
    while(i<MessageSum)
    {
        //多线程安全函数
        tracker_get_connection_r(pTrackerServer);
        if ( pTrackerServer->sock <= 0 )
        {      
            sleep(1);
            continue;
        }

        printf("DEBUG :get tracker conn ok, i = %d/n", i);
        store_path_index = 0;

        if ((result=tracker_query_storage_store(pTrackerServer, /
                        &storageServer, &store_path_index )) != 0)
        {
            //查询tracker获取storage失败,重连tracker
            printf("ERROR :tracker_query_storage fail, " /
                    "error no: %d, error info: %s, i = %d/n", /
                    result, strerror(result), i);
            fdfs_quit(pTrackerServer);
            tracker_disconnect_server(pTrackerServer);
            sleep(1);
            continue;
        }

        printf("DEBUG :tracker_query_storage_store ok/n");

        //if(storageServer.group_name.sizeof())
        /*if( sizeof(storageServer.group_name) )
          {
          printf("INFO : infomation get faile !");
          continue;
          }*/

        printf("group_name=%s, ip_addr=%s, port=%d/n", /
                storageServer.group_name, /
                storageServer.ip_addr, /
                storageServer.port);

        if ((result=tracker_connect_server(&storageServer)) != 0)
        {
            //tracker给了一个连不上的storage,重连tracker
            printf("DEBUG :conn storage failed and continue/n");
            fdfs_quit(pTrackerServer);
            tracker_disconnect_server(pTrackerServer);

            sleep(1);
            continue;
        }

        printf("DEBUG :conn storage ok/n");
        //1下面保持tracker和storage的各1个长连接,本线程固定跟一个storage交互,出错后才返回重连进行容灾
        //2实际中如果是大文件没必要保持长连接,则下面这个for循环去掉成顺序执行,出错时continue回while循环去重连tracker和storage
        for(;i<MessageSum;i++)
        {
            //以上传为例,上传目前有3类,根据应用自己选一类即可,参见版本自带的fdfs_test.c
            //if (strcmp(operation, "upload") == 0)
            {
                printf("DEBUG :to upload a file, i = %d/n", i);
                strcpy(group_name, "");
                result = storage_upload_by_filename(pTrackerServer, /
                        &storageServer, store_path_index, /
                        local_filename, NULL, /
                        NULL, 0, /
                        group_name, remote_filename);    

                //下面的出错或成功处理,跟上述上传种类无关,通用的
                if (result != 0)
                {
                    printf("INFO :storage_upload_by_filename fail, " /
                            "error no: %d, error info: %s/n", /
                            result, strerror(result));
                    fdfs_quit(&storageServer);
                    tracker_disconnect_server(&storageServer);
                    fdfs_quit(pTrackerServer);
                    tracker_disconnect_server(pTrackerServer);

                    //上传次数的统计,测试用
                    pthread_mutex_lock(&theSumMutex);
                    nTradeFailed ++;
                    nSum++;
                    pthread_mutex_unlock(&theSumMutex); 
                    break;
                }

                sprintf(file_id, "%s/%s", group_name, remote_filename);
                url_len = sprintf(file_url, "http://%s:%d/%s", /
                        pTrackerServer->ip_addr, /
                        g_tracker_server_http_port, file_id);
                /*
                   if (g_anti_steal_token)
                   {
                   ts = time(NULL);
                   fdfs_http_gen_token(&g_anti_steal_secret_key, file_id, /
                   ts, token);
                   sprintf(file_url + url_len, "?token=%s&ts=%d", /
                   token, (int)ts);
                   }*/

                printf("DEBUG :upload a file ok, i = %d/n", i);
                memset(buff, 0, sizeof(buff));
                base64_decode_auto(&context, remote_filename + FDFS_FILE_PATH_LEN, /
                        strlen(remote_filename) - FDFS_FILE_PATH_LEN /
                        - (FDFS_FILE_EXT_NAME_MAX_LEN + 1), buff, &len);
                printf("INFO :group_name=%s, remote_filename=%s/n", /
                        group_name, remote_filename);
                printf("INFO :file timestamp=%d/n", buff2int(buff+sizeof(int)));
                printf("INFO :file size="INT64_PRINTF_FORMAT"/n", /
                        buff2long(buff+sizeof(int)*2));
                printf("INFO :file url: %s/n", file_url);

                pthread_mutex_lock(&theSumMutex);
                nTradeOK ++;
                nSum++;
                pthread_mutex_unlock(&theSumMutex);

            }           
        }

        fdfs_quit(&storageServer);
        tracker_disconnect_server(&storageServer);
        fdfs_quit(pTrackerServer);
        tracker_disconnect_server(pTrackerServer);

 

        printf("quit storage ok/n");
    }

    int nEndTime=time(NULL);
    pthread_mutex_lock(&theSumMutex);
    OverThread ++;
    nTimeAllUsed += (nEndTime - nStartTime);
    pthread_mutex_unlock(&theSumMutex); 

    printf("quit thread ok/n");
    return NULL;
}


void
StartApp ( )
{
    int m;
    char *sParam;
    int result;

    printf("IN StartApp/n");

    log_init();
    //init here
    if ( (result = fdfs_client_init(conf_filename)) != 0)
    {
        return;
    }

    for ( m = 0; m < nThreadCount; m++ )
    {
        printf( "DEBUG :printf the thread number:(%d)/n", m );
        CreateThread ( MultiThreadTest, (void*)&nReqCount );
    } 

    printf( "INFO :wait all thread(%d) to exit/n", nThreadCount);
    printf( "INFO :wait all thread(%d) to exit/n", OverThread);

    while (OverThread < nThreadCount)
    {
        sleep(1);
    }

    int iTimeUsed= nTimeAllUsed/nThreadCount;
    if( iTimeUsed==0 ) iTimeUsed = 1;

    printf("-------------------operate is over------------------------------/n");
    printf("send %d request ,OK[%d],failed[%d],TimeUsed=%d,speed=%d(r/s)/n",
            nSum, nTradeOK, nTradeFailed, iTimeUsed, nSum/iTimeUsed );

    tracker_close_all_connections();
    fdfs_client_destroy();

    return;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值