#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;
}
TCP发包客户端,可用于性能测试
最新推荐文章于 2024-08-01 08:39:15 发布