TCP发包客户端,可用于性能测试

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/resource.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <sys/time.h>
#include <pthread.h>
#include <errno.h>
#include <signal.h>
#include <netinet/tcp.h>


/*由于微秒定时器在计算机上精度是不准确的, 发送数据包的速度也和计算机的性能及网络
  带宽及拥塞的程度有关,因此需要在不同的计算机上调整下列参数,以达到数据包的发送
  速度, 最主要的调整参数是TIME_INTERVAL_BETWEEN_SEND,即发送数据包的时间间隔*/
int     TIME_WAIT_FOR_CONNECT =  40;  /*等待所有连接建立完成时间: 秒*/
#define TIME_WAIT_FOR_CLIENT_OVER     1200 /*开始发送数据包到客户端结束退出时间: 秒*/
int TIME_INTERVAL_BETWEEN_CONNECT = 10000; /*每个线程每个TCP连接建立间隔: 微秒*/
int     TIME_INTERVAL_BETWEEN_SEND = 500;  /*每个线程发送数据包的间隔:    微秒*/



/*通过下面的宏可以调整发包的总数*/
int      MAX_TRHEAD = 8;        /*发包线程的个数*/
int      MAX_SOCKET_NUM = 500;  /*每个线程建立socket的个数*/
#define MSG_NUM_PER_CONNECT 2000 /*每个连接发送包的个数*/

int      SEND_TIME = 100;

int      LOOP_CONTINUE = 1;



#define BUF_SIZE 8192	       /*buffer的大小*/
#define MAXEPOLLSIZE 100000  /*最大的socket个数*/

#define TRUE 1
#define FALSE 0

#define INVALID_SOCKET -1

#define MAX_CONNECT_RETRY    10

/************************GPS DEFINE START *************************/


//#define GPS_DATA_SEND   //is need send GPS data to server, please open is macro

typedef unsigned short  uint16_t;

typedef unsigned char  uint8_t;

typedef unsigned int    uint32_t;

#define GPS_TYPE_POS 0x10
#define GPS_TYPE_KEEPALIVE 0x1A

typedef struct gps_time_t
{
    uint8_t year;
    uint8_t month;
    uint8_t day;
    uint8_t hour;
    uint8_t minute;
    uint8_t second;
} __attribute__ ((packed)) gps_time_t;

/* GPS POS info */
typedef struct
{
    gps_time_t time;
    uint32_t   latitude;
    uint32_t   longitude;
    uint8_t    speed;
    uint16_t   direct;
    uint8_t    resv[3];
    uint32_t   state;
} __attribute__ ((packed)) gps_msg_pos_t;




typedef struct
{
    uint16_t start;
    uint8_t  len;
    uint8_t  volt_calss;
    uint8_t  gsm_sig_level;
    uint8_t  uid[8];
    uint16_t seq;
    uint8_t  type;
    uint8_t  data[0];
} __attribute__ ((packed)) gps_msg_head_t;


typedef struct
{
    uint8_t  locate_stat;
    uint8_t  satellite_num;
    uint8_t  data[0];
} __attribute__ ((packed))  heartbeat_info_head_t;



#define GPS_MSG_HEAD_LENT            (sizeof(gps_msg_head_t))
#define GPS_MSG_POS_LENT             (sizeof(gps_msg_pos_t))

#define GPS_HEARTBEAT_INFO_HEAD_LENT (sizeof(heartbeat_info_head_t))
#define GPS_MSG_END_LABEL_LENT        2

#define GPS_POS_MSG_LENGTH   (GPS_MSG_HEAD_LENT + GPS_MSG_POS_LENT   \
                              + GPS_MSG_END_LABEL_LENT)

#define GPS_HEARTBEAT_MSG_LENGTH(n) (GPS_MSG_HEAD_LENT  + GPS_HEARTBEAT_INFO_HEAD_LENT \
                                     + (n) + GPS_MSG_END_LABEL_LENT)

#define GPS_HEADER_START_LABEL   0x6868
#define GPS_HEADER_END_LABEL     0x0D0A

#define GPS_MAX_LATITUDE         162000000
#define GPS_MAX_LONGITUDE        324000000
#define GPS_MAX_SPEED            255
#define GPS_MAX_DIRECT           360

#define GPS_MAX_VOLT_CLASS       6
#define GPS_MAX_GSM_LEVEL        4

/************************GPS DEFINE END  *************************/

typedef  struct
{
    struct sockaddr_in sock_addr;
    int    thread_index;
} server_struct;

/*+++++++++++++++++++++++GLOBAL PARAMETERS START +++++++++++++++++++++*/
#define MAX_THREAD_NUMBER   3000
pthread_t thread[MAX_THREAD_NUMBER];
pthread_t thread_wait;

pthread_mutex_t connet_count_lock = PTHREAD_MUTEX_INITIALIZER;

int connet_count = 0;
int packet_count = 0;
char buf[BUF_SIZE] = "test tcp client.............";
int BUFFER_LENGTH = 20;


server_struct server[MAX_THREAD_NUMBER];
int timecount = 0;
pthread_t thread_count;

pthread_cond_t send_msg_cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t send_msg_lock = PTHREAD_MUTEX_INITIALIZER;


pthread_cond_t start_cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t start_lock = PTHREAD_MUTEX_INITIALIZER;


int myport;

/*+++++++++++++++++++++++GLOBAL PARAMETERS START +++++++++++++++++++++*/


void* thread_func(void* sk);
void* thread_wait_fuc(void* arg);
static void *handle_count(void* arg);


/************************GPS CODE START  *************************/
int gps_get_time(gps_time_t *gps_time)
{

    time_t          timep;
    struct tm       nowtime;


    time(&timep);

    /*获取当地时间, 如果以后用其他时间,如UTC时间, 可以更改用其他函数*/
    if(NULL == localtime_r(&timep, &nowtime))
    {
        printf("get time failed ! \n");
        return FALSE;
    }

    gps_time->day = (nowtime.tm_year + 1900 - 2000); /*时间是从2000年开始的时间, 如2012=> 12*/
    gps_time->month  = nowtime.tm_mon + 1; /*获得的时间是0~11*/
    gps_time->day    = nowtime.tm_mday;
    gps_time->hour   = nowtime.tm_hour;
    gps_time->minute = nowtime.tm_min;
    gps_time->second = nowtime.tm_sec;

    return TRUE;
}

/*
   function  get_gps_pos_msg
   This function is used for building the GPS position message, the caller should
   free the return buffer when it did not used it.

   parameter:
   @latitude  纬度,占用4个字节,表示定位数据的纬度值。数值范围0至162000000,表示0度到90度的范围
   @longitude 经度, 占用4个字节,表示定位数据的经度值。数值范围0至324000000,表示0度到180度的范围
   @speed     速度 占用1个字节,表示GPS的运行速度,表示范围0~255,单位:公里/小时,
   @direct    航向 占用2个字节,表示GPS的运行方向,表示范围0~360,单位:度,以正北为0度,顺时针
   @state     状态位 占用4个字节,用来表示手机的各种状态信息.把4个字节看作32位,最低位为0位,
              最高位为31位,传送时先传送高位,再传送低位
   @uid       终端ID 十六进制,采用的是终端的15位IMEI号作为终端ID.例IMEI号为123456789123456,
              则终端ID 为:0x01 0x23 0x45 0x67 0x89 0x12 0x34 0x56.
   @uid_len   终端ID长度, 固定为8
   @seq       信息序列号 开机后发送的第一条GPRS数据(包括心跳包和定位数据)序列号为‘1’,
              之后每次发送数据(包括心跳包和定位数据)序列号都自动加1
   @rtlength  返回数据包长度
*/
char*  get_gps_pos_msg(uint32_t latitude, uint32_t  longitude,
                       uint8_t speed, uint16_t direct, uint32_t state,
                       uint8_t uid[8], uint8_t uid_len, uint16_t seq, uint8_t* rtlength )
{

    char           *buffer = NULL;
    gps_msg_head_t *gps_msg_head_ptr;
    gps_msg_pos_t  *gps_pos_ptr;
    time_t          timep;
    struct tm       nowtime;
    uint16_t       *endlable;

    buffer = malloc(GPS_POS_MSG_LENGTH);

    if(NULL == buffer)
    {
        printf("get_gps_pos_msg: malloc buffer failed! \n");
        return NULL;
    }

    gps_msg_head_ptr = (gps_msg_head_t*)buffer;

    gps_msg_head_ptr->start = htons(GPS_HEADER_START_LABEL);
    gps_msg_head_ptr->len   = 0x25;
    gps_msg_head_ptr->volt_calss = 0; /*This byte is reserved in pos message*/
    gps_msg_head_ptr->gsm_sig_level = 0; /*This byte is reserved in pos message*/
    memcpy(&(gps_msg_head_ptr->uid[0]), uid, uid_len);
    gps_msg_head_ptr->seq = htons(seq);
    gps_msg_head_ptr->type = GPS_TYPE_POS;

    gps_pos_ptr = (gps_msg_pos_t*)gps_msg_head_ptr->data;


    if(FALSE == gps_get_time(&gps_pos_ptr->time))
    {
        return NULL;
    }

    gps_pos_ptr->latitude   = htonl(latitude);
    gps_pos_ptr->longitude  = htonl(longitude);
    gps_pos_ptr->speed      = speed;
    gps_pos_ptr->direct     = htons(direct);
    gps_pos_ptr->resv[0]    = 0;
    gps_pos_ptr->resv[1]    = 0;
    gps_pos_ptr->resv[2]    = 0;
    gps_pos_ptr->state      = htonl(state);

    endlable = (uint16_t* )(buffer + (GPS_MSG_HEAD_LENT + GPS_MSG_POS_LENT));
    *endlable  = htons(GPS_HEADER_END_LABEL);

    *rtlength = GPS_POS_MSG_LENGTH;

    return buffer;

}


/*
   function  get_gps_heartbeat_msg
   This function is used for building the GPS heart beat message, the caller should
   free the return buffer when it did not used it.

   parameter:
   @volt_calss    电压等级 十进制,范围为0~6,标示电压大小由低到高.
   @gsm_sig_level GSM信号强度等级
   @uid[8]    终端ID 十六进制,采用的是终端的15位IMEI号作为终端ID.例IMEI号为123456789123456,
              则终端ID 为:0x01 0x23 0x45 0x67 0x89 0x12 0x34 0x56.
   @uid_len   终端ID长度, 固定为8
   @seq       信息序列号 开机后发送的第一条GPRS数据(包括心跳包和定位数据)序列号为‘1’,
              之后每次发送数据(包括心跳包和定位数据)序列号都自动加1
   @satellite_num  终端搜到卫星个数
   @locate_stat    定位状态
   @satellite_info 卫星信噪比, 是数组,数组大小根据卫星个数而定, 最多12个
   @rtlength  返回数据包长度

*/
char* get_gps_heartbeat_msg(uint8_t volt_calss, uint8_t gsm_sig_level,
                            uint8_t uid[8], uint8_t uid_len, uint16_t seq,
                            uint8_t satellite_num, uint8_t locate_stat,
                            uint8_t *satellite_info, uint8_t *retlen)
{
    char *buffer;
    uint8_t buf_len;
    gps_msg_head_t *gps_msg_head_ptr;
    heartbeat_info_head_t  *heartbeat_info_ptr;
    uint16_t       *endlable;


    buf_len = GPS_HEARTBEAT_MSG_LENGTH(satellite_num);
    buffer = malloc(buf_len);

    if(NULL == buffer)
    {
        printf("get_gps_heartbeat_msg: malloc buffer failed! \n");
        return NULL;
    }

    gps_msg_head_ptr = (gps_msg_head_t*)buffer;
    gps_msg_head_ptr->start = htons(GPS_HEADER_START_LABEL);
    gps_msg_head_ptr->len   = 15 + satellite_num;
    gps_msg_head_ptr->volt_calss = volt_calss;
    gps_msg_head_ptr->gsm_sig_level = gsm_sig_level;
    memcpy(&(gps_msg_head_ptr->uid[0]), uid, uid_len);
    gps_msg_head_ptr->seq = htons(seq);
    gps_msg_head_ptr->type = GPS_TYPE_KEEPALIVE;

    heartbeat_info_ptr = (heartbeat_info_head_t  *)gps_msg_head_ptr->data;

    heartbeat_info_ptr->locate_stat = locate_stat;
    heartbeat_info_ptr->satellite_num = satellite_num;

    memcpy(heartbeat_info_ptr->data, satellite_info, satellite_num);

    endlable = (uint16_t *)(buffer + GPS_MSG_HEAD_LENT
                            + GPS_HEARTBEAT_INFO_HEAD_LENT + satellite_num);

    *endlable = htons(GPS_HEADER_END_LABEL);

    *retlen  = buf_len;

    return buffer;


}

/************************GPS CODE END  *************************/


void handle_pipe(int sig)
{
    // printf("SIGPIPE signal %d\n", sig);
}


int main(int argc, char *argv[])
{
    int num;
    int i;
    struct rlimit rt;
    pid_t pc, pr;
    //.....
    struct hostent *he;

    struct sigaction action;
    //...IPv4....
    //struct sockaddr_in server;

    if(argc != 10)
    {
      printf("Usage: %s <IP Address> <port(0-65535)> <thread_num(0 - 3000)> \
		        <sock_num per thread > <send interval(microsecond) > \
		        <send message time (second)> <wait_time for connect finish(second)> \
		        <socket connect interval(microsecond)> <send buffer length(0~8192)>\n", argv[0]);      

      exit(1);
    }

    //..gethostbyname()..........
    if((he = gethostbyname(argv[1])) == NULL)
    {
        printf("gethostbyname() error\n");
        exit(1);
    }

    myport = atoi(argv[2]);
    MAX_TRHEAD = atoi(argv[3]);
    MAX_SOCKET_NUM = atoi(argv[4]);
    TIME_INTERVAL_BETWEEN_SEND = atoi(argv[5]);
    SEND_TIME   = atoi(argv[6]);
    TIME_WAIT_FOR_CONNECT = atoi(argv[7]);
    TIME_INTERVAL_BETWEEN_CONNECT = atoi(argv[8]);
    BUFFER_LENGTH =  atoi(argv[9]);

    //install signal action

    action.sa_handler = handle_pipe;
    sigemptyset(&action.sa_mask);
    action.sa_flags = 0;
    sigaction(SIGPIPE, &action, NULL);

    //...server....
    bzero(&server, sizeof(server));

    for(i = 0; i < MAX_TRHEAD; i ++)
    {
        server[i].sock_addr.sin_family = AF_INET;
        server[i].sock_addr.sin_port = htons(myport);
        server[i].sock_addr.sin_addr = *((struct in_addr *)he->h_addr);
        server[i].thread_index = i;
    }

    rt.rlim_max = rt.rlim_cur = MAXEPOLLSIZE;

    if (setrlimit(RLIMIT_NOFILE, &rt) == -1)
    {
        perror("setrlimit");
        exit(1);
    }

    pthread_mutex_init (&(send_msg_lock), NULL);
    pthread_cond_init (&send_msg_cond, NULL);

    pthread_mutex_init (&(start_lock), NULL);
    pthread_cond_init (&start_cond, NULL);

    pthread_mutex_init (&connet_count_lock, NULL);

    if (pthread_create(&thread_count, NULL, &handle_count, NULL) != 0)
    {
#ifdef DEBUG_TILERA
        tmc_task_die("pthread_create() failed.");
#endif
    }



    for (i = 0; i < MAX_TRHEAD; i++)
    {
        if (pthread_create(&thread[i], NULL, thread_func, (void*)&server[i]) != 0)
        {
            printf("pthread_create() failed.\n");
            exit(1);
        }

    }

    if (pthread_create(&thread_wait, NULL, thread_wait_fuc, NULL) != 0)
    {
        printf("pthread_create() failed.");
    }

    pthread_mutex_lock (&start_lock);
    pthread_cond_wait (&start_cond, &start_lock);
    pthread_mutex_unlock (&start_lock);

    printf("start cond \n");

    sleep(SEND_TIME);

    LOOP_CONTINUE = 0;
    
    printf("===============================================================\n \n");
    printf("Packet counts: %d  speed: %d packets/second \n", packet_count, packet_count / SEND_TIME);
    printf("===============================================================\n \n");
    
    sleep(40);

    exit(1);


    if(pthread_join(thread_wait, NULL) != 0)
    {
        printf("pthread_join() failed.");
    }

    return 0;
}

void* thread_wait_fuc(void *arg)
{
    int i;

    sleep(TIME_WAIT_FOR_CONNECT);
    /*starting gun*/
    printf("................START TO SEDN PACKETS............... \n");

    for(i = 0; i < MAX_TRHEAD; i++)
    {
        pthread_mutex_lock (&send_msg_lock);
        pthread_cond_signal (&send_msg_cond);
        pthread_mutex_unlock (&send_msg_lock);
    }

    pthread_mutex_lock (&start_lock);
    pthread_cond_signal (&start_cond);
    pthread_mutex_unlock (&start_lock);

    sleep(TIME_WAIT_FOR_CLIENT_OVER);
    pthread_exit(0);
}

void* thread_func(void* sk)
{
    struct sockaddr* t_ser;
    server_struct  *server_st;
    int thread_index;
    int sockfd[MAX_SOCKET_NUM];
    int i, j = 0;
    int send_num;
    char *buffer;
    int sndlen;
    int  connect_retry = 0;
    int flag = 1;

    uint32_t latitude, longitude, state;
    uint8_t  speed, buff_len;
    uint16_t direct;
    uint8_t uid[8] = {0x01, 0x23, 0x45, 0x67, 0x89, 0x12, 0x34, 0x56};

    uint8_t upnum, lownum;



    server_st = (server_struct*)sk;
    thread_index = server_st->thread_index;

    uid[5] = (uint8_t)thread_index; /*将第6位写为线程的INDEX,以免不同线程重复*/

    t_ser = (struct sockaddr *)(&(server_st->sock_addr));

    for(i = 0; i < MAX_SOCKET_NUM; i++)
    {

        if((sockfd[i] = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
        {
            printf("socket() error %d  socket %d\n", errno, i );
            usleep(TIME_INTERVAL_BETWEEN_CONNECT);
            //--i;
            continue;
        }

        if(-1 == setsockopt( sockfd[i], IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag) ))
        {
            printf("setsockopt() error %d  socket %d\n", errno, i );
            continue;
        }

        
        if(connect(sockfd[i], t_ser, sizeof(struct sockaddr_in)) == -1)
        {
            
            printf("connect() error %d  socket %d \n", errno , i);
            close(sockfd[i]);
            
            if( connect_retry < MAX_CONNECT_RETRY)
            {
                connect_retry++;
                --i;
                printf("connect again socket %d\n", i);
            }
            else
            {
                connect_retry = 0;
            }
            usleep(TIME_INTERVAL_BETWEEN_CONNECT);
            continue;
        }
        else
        {
            pthread_mutex_lock(&connet_count_lock);
            connet_count++;
            pthread_mutex_unlock (&connet_count_lock);
            connect_retry = 0;
            //printf("tcp connect count %d\n",connet_count);
        }

        usleep(TIME_INTERVAL_BETWEEN_CONNECT);
    }

    pthread_mutex_lock (&send_msg_lock);
    pthread_cond_wait (&send_msg_cond, &send_msg_lock);
    pthread_mutex_unlock (&send_msg_lock);

#if 1
#if 0

    for(j = 0; j < MSG_NUM_PER_CONNECT; j++)
#endif
    while(LOOP_CONTINUE)
    {
        j++;

        for(i = 0; i < MAX_SOCKET_NUM; i++)
        {


#ifdef   GPS_DATA_SEND
            /*如果需要发送GPS数据包,在这里可以调用GPS的接口函数获得GPS数据包并且发送
              这里只是实现了position数据的发送, 如果还要heart beat数据,可以根据需要增加*/
            /*下面的数据采用随机数的方式修改*/
            latitude = rand() % (GPS_MAX_LATITUDE + 1);
            longitude = rand() % (GPS_MAX_LONGITUDE + 1);
            state     = rand();   /*状态这个字段需要参考协议填写,这里暂时添随机数*/
            speed  = rand() % (GPS_MAX_SPEED + 1);
            direct = rand() % (GPS_MAX_DIRECT + 1);

            upnum = (uint8_t)(i >> 8);
            lownum = (uint8_t)i;
            /*将最后两位改为和socket关联, 以免同一线程内重复*/
            uid[6] = upnum;
            uid[7] = lownum;
            /*构造位置信息数据包*/
            buffer =  get_gps_pos_msg(latitude, longitude, speed, direct, state,
                                      uid, 8, j + 1,  &buff_len );

#else

            buffer = buf;
            buff_len = BUFFER_LENGTH;
#endif
            if(LOOP_CONTINUE)
            {

                if(INVALID_SOCKET !=  sockfd[i])
                {
                    if((sndlen = send(sockfd[i], buffer, buff_len, 0)) != -1)
                    {
                        packet_count++;

                    }
                    else if((-1 == sndlen) && (EAGAIN  == errno))
                    {
                        //the socket buffer is full, ignor this buffer

                        continue;
                    }
                    else
                    {
                        perror("send error ");
                        close(sockfd[i]);

                        pthread_mutex_lock(&connet_count_lock);
                        connet_count--;
                        pthread_mutex_unlock (&connet_count_lock);
                        
                        sockfd[i] = INVALID_SOCKET;
                    }


                }
                else
                {
#ifdef   GPS_DATA_SEND
                    free(buffer);
                    continue;
#endif
                }
            }
            else
            {
                break;
            }

#ifdef   GPS_DATA_SEND
            free(buffer);
#endif

            usleep(TIME_INTERVAL_BETWEEN_SEND);

        }

        //usleep(800);
#if 0

        if (i % 5 == 0)
        {
            close(sockfd);
        }

#endif
#endif
    }

   // printf("sleep ................\n");
    sleep(20);

    for(i = 0; i < MAX_SOCKET_NUM; i++)
    {
        // close(sockfd[i]);
        if(INVALID_SOCKET != sockfd[i])
        {
            close(sockfd[i]);
            pthread_mutex_lock(&connet_count_lock);
            connet_count--;
            pthread_mutex_unlock (&connet_count_lock);
            usleep(200);
        }
    }

    //printf("close the socket........\n");
    pthread_exit(0);
    return 0;
}

/*统计发送的数据*/
static void *handle_count(void* arg)
{
    int precount, speed;

    while(1)
    {
        precount = packet_count;
        sleep(5);
        //timecount += 5;
        //printf("The tcp connection count is %d\n",count_tcp);
        //printf("The received packets count is %d, time %d\n",msgcount, timecount);
        speed = packet_count - precount ;
        printf("The send speed  is %d packets/5 second, connects %d \n", speed, connet_count);
    }

    return NULL;
}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值